aiwiki.page
English
Computer Science / Software & Programming / cascading-style-sheets

Cascading Style Sheets

CSS is a style sheet language that controls how markup-based documents, mainly web pages, are presented, separating appearance from structure.

13 keywords4 linked from6 not yet writtenWritten by AI
HTMLWorld Wide WebJavaScriptCERNPrintingDisabilityUnicodeWorld Wide Web C…Cascading…

Cascading Style Sheets (CSS) is a style sheet language for describing how documents written in markup languages such as HTML are presented on screen, in print, and in other media. Its central idea is the separation of structure from presentation: the markup says what a piece of content is, and the style rules say how it should look. Because the World Wide Web is built on this separation, CSS is one of the core technologies of the web, alongside HTML and JavaScript.

The name refers to the cascade, the process by which declarations from several style sources, such as the browser's defaults, the author's sheets and user preferences, are combined and resolved when they conflict. Its development began at CERN in the mid-1990s, and it has since been maintained by the W3C CSS Working Group as a growing collection of modules, each of which reaches maturity at its own pace. As a result, CSS has grown from a small set of text and color properties into a system that handles layout, responsive adaptation, animation, and color management.

This entry first covers the origins and standardization of CSS, then its syntax, selectors, and the cascade and inheritance model. It goes on to value computation, layout, responsive design, visual effects, and animation, followed by print and accessibility, tooling, browser implementation, and its relations with other web technologies. It ends with criticisms, open problems, and future directions.

Definition and scope

Cascading Style Sheets (CSS) is a declarative language for describing how structured documents are presented. Its main targets are markup languages such as HTML, XML, and SVG, and its syntax is also used with other document formats. A style sheet does not change what a document says. It states how elements should look and where they should appear, including fonts, colours, spacing, and layout. Because the language is declarative, an author lists the desired results and the user agent (usually a browser) decides how to produce them. This differs from a procedural program, which gives the computer step-by-step instructions. CSS is usually paired with JavaScript for behaviour, but CSS itself does not perform computation of that kind.

The central principle behind CSS is the separation of content from presentation. Markup should describe structure and meaning: this is a heading, this is a list, this is a quotation. Visual treatment is kept in one or more separate style sheets. This separation has practical effects. A single style sheet can govern thousands of pages, so a site-wide redesign can be made by editing one file instead of every document. Authors can concentrate on writing and structure while designers work on appearance without touching the text. The same markup can also be reused in different contexts, such as a phone screen, a printed page, or speech output, with a different set of rules for each. Earlier web pages mixed meaning and appearance through presentational elements and attributes, such as the font element. Later versions of HTML deprecated these features in favour of CSS.

CSS uses a small set of terms with precise meanings. A style sheet is made up of rules, and it may also contain at-rules, which are statements beginning with an @ sign that control other behaviour, such as conditional blocks or imports. A style rule has two parts: a selector, which identifies the elements the rule applies to, and a declaration block enclosed in curly braces. Inside the block, each declaration pairs a property, which is a named aspect of presentation such as color or font-size, with a value. The term "declaration" refers to the whole property-and-value pair, not to the property name alone. In the following example, h1 is the selector, color and font-size are properties, and the two lines inside the braces are declarations.

h1 {
  color: navy;
  font-size: 2rem;
}

CSS is not limited to visual display on screens. The language defines media types, which are categories of output medium, so that a style sheet can be applied selectively. The screen type covers computer and mobile displays. The print type covers paged output, such as paper printing, and is closely tied to the rules for printing and page layout discussed elsewhere. The speech type covers audio output, such as text read aloud by a synthesiser; earlier specifications called this the aural type. Media types allow one document to be presented in several forms without changing its markup. Support for these forms is important for users who rely on assistive technology, a topic connected to disability and accessibility.

Within this scope, CSS concerns presentation only. It does not define the structure of a document, which is the job of the markup language, nor does it define the scripted behaviour of a page. These boundaries are part of what makes the separation between content and style workable in practice.

Origins and early development

Proposal at CERN

CSS grew out of a practical gap in the early Web. While working at CERN, Håkon Wium Lie found that the Web was starting to be used for electronic publishing but had no way to style documents. Pages could not express a newspaper-style arrangement of columns, for example. While still at CERN in 1994, Lie put forward the idea of CSS. His background helped shape the idea: earlier work on personalised newspaper presentation at the MIT Media Laboratory led him to conclude that the Web needed a separate style sheet language .

The idea was not the only one in circulation. Other styling proposals, such as Style Sheets for HTML and JSSS, appeared around the same time, and CSS ultimately prevailed. What set Lie's approach apart was its handling of the cascade: the author's wishes, the reader's wishes, and the capabilities of the display device and browser had to be combined in a defined way . Some histories date his first public proposal to 10 October 1994 , though sources differ on such details.

Informal drafts and early collaborators

Lie's design then circulated through a series of informal drafts, beginning in 1995. Among those who answered the first draft was Bert Bos, who was building Argo, a highly customisable browser with style sheet support. He decided to join forces with Lie. The collaboration of Lie and Bos produced the initial design on which the later specifications were built.

Adoption by the W3C (1994–1995)

The World Wide Web Consortium was founded in 1994 to coordinate Web standards. At the end of 1995 it set up the HTML Editorial Review Board to ratify future HTML specifications. Because style sheets fell within the interests of the new group's members, the CSS specification was taken up as a work item with the goal of making it into a W3C Recommendation. Industry pressure also mattered. After Microsoft announced CSS support in its browser, W3C sought Netscape's participation, since browsers supporting different specifications could pull the Web in different directions. Microsoft's Internet Explorer 3, released in August 1996, became the first commercial browser with CSS support, even though the CSS1 specification had not yet become a W3C Recommendation.

CSS level 1 and level 2

The first specification reached Proposed Recommendation status on 12 November 1996 . It became a W3C Recommendation on 17 December 1996 . Its scope was deliberately modest: it addressed attributes such as fonts, colours and spacing applied to HTML documents , and it expressed style in common desktop publishing terminology.

CSS2 was developed by a dedicated working group formed in February 1997 to address features CSS1 had left out . It was issued as a Proposed Recommendation on 24 March 1998 , and as a W3C Recommendation on 12 May 1998 . CSS2 builds on CSS1, adding many new features while remaining fully backwards compatible. Its additions included better print formatting, positioned and layered elements, and downloadable fonts , as well as aural properties for speech output . It also introduced media-specific style sheets for visual browsers, printers, braille devices and handheld devices .

Standardization and the module model

CSS is developed by the CSS Working Group at the W3C, and each specification moves through a fixed set of maturity stages. The stage labels, from the least to the most settled, include First Public Working Draft, Working Draft, Candidate Recommendation, Candidate Recommendation Draft, Proposed Recommendation, and Recommendation. The working group's status page lists these codes in that order. W3C indicates the maturity of specifications by a status code. The CSS working group uses the following, from least to most stable: A Working Draft is an early publication aimed at collecting outside review. It is not a sign that consensus has already been reached, A Working Draft generally represents work in progress and a commitment by W3C to pursue work in a particular area. The label "Working Draft" does not imply consensus within W3C about the document.

From Candidate Recommendation to Recommendation

The Candidate Recommendation stage is a testing phase. Here the effort goes into checking whether the specification can be implemented consistently, not into grading browsers. Demonstration of two correct, independent implementations of each feature is required to exit CR, so in this phase the WG builds a test suite and generates implementation reports. The CSS charter repeats the same gate for every module, requiring at least two independent implementations of every feature before a module can advance. A specification that clears this gate becomes a Proposed Recommendation, which is sent to the Advisory Committee for review. A Proposed Recommendation is a Candidate Recommendation that has benefitted from implementation experience and has been sent to the Advisory Committee for review. Formal approval then confers the Recommendation label. That label signals that the document is expected to need few further changes, At this point there should need to be no more changes.

From monolithic levels to independent modules

CSS was first organized into numbered levels, and that approach caused friction. CSS2 became a Recommendation before the Candidate Recommendation stage existed. As implementers reported problems, the working group decided not to keep extending an unwieldy errata list. It issued a revision, CSS2.1, which takes precedence wherever the two documents conflict. Although the CSS2 specification is technically a W3C Recommendation, it passed into the Recommendation stage before the W3C had defined the Candidate Recommendation stage. Over time implementation experience and further review has brought to light many problems in the CSS2 specification, so instead of expanding an already unwieldy errata list, the CSS Working Group chose to define CSS Level 2 Revision 1 (CSS2.1).

Later work was split into modules, each with its own maturity and schedule. Modules can supersede specific parts of earlier levels. For example, Selectors Level 3 replaces CSS2§5 and CSS2§6.4.3, defining an extended range of selectors. A module can also extend a predecessor while the predecessor remains in use. Selectors Level 4 extends Selectors Level 3 by introducing new pseudo-classes, pseudo-elements, and combinators. Because modules advance at different speeds, there is no single document that defines "CSS Level 3" or later in full. The working group explains that since different CSS modules are at different levels of stability, the CSS Working Group has chosen to publish this profile to define the current scope and state of Cascading Style Sheets at a given date.

Annual snapshots

The yearly CSS Snapshot is the working group's way of fixing a reference point for the language. Each snapshot is a W3C Group Note rather than a Recommendation, and it gathers the modules that together describe CSS at a particular date. The 2020 snapshot was restrictive: This profile includes only specifications that we consider stable and for which we have enough implementation experience that we are sure of that stability. Later snapshots loosened this rule and sorted modules into tiers by maturity. The 2023 edition, for instance, listed a category of Fairly Stable Modules with limited implementation experience. The 2026 edition, published as a Group Note on 22 June 2026, states that its main readers are implementers rather than authors, since it includes modules by specification stability, not Web browser adoption rate.

Working group and gating

The CSS Working Group develops the specifications together with browser vendors and invited experts. Browser implementation is therefore central to the process: a module does not advance merely because its text is finished. It must be shown to work interoperably across engines before it can become a Recommendation. The result is that a snapshot can list a module as stable while some of its features are still uneven across browsers, a gap that the stage model is designed to narrow but cannot fully close.

Syntax and parsing

Rules, selectors and declarations

A style sheet is a list of rules, and the parser treats each rule as either an at-rule or a qualified rule. A qualified rule starts with a prelude then has a {}-wrapped block containing a sequence of declarations. In a style rule, the prelude is the selector that decides which elements the block applies to. Within the block, each declaration is a property identifier followed by a colon and a value, and the semicolon separates one declaration from the next. The final declaration in a block may omit its semicolon, although authors usually keep it so that adding a line later is less error-prone. Whitespace around declarations carries no meaning, and an empty block is valid.

At-rules

At-rules begin with an at-sign, @ (U+0040 COMMERCIAL AT), followed by an identifier. Their syntax is defined in the core syntax module, while the meaning of each at-rule is defined in the module that introduces it. They fall into two shapes. Statement at-rules, such as @import and @layer in its plain form, end with a semicolon. Block at-rules, such as @media, @supports and @keyframes, carry a {}-block. Block at-rules can contain nested qualified rules, at-rules, or declarations. Nested at-rules and style rules are a relatively recent addition to the language, and an at-rule's meaning depends on where it appears. @import, for example, must come before ordinary rules, so a late @import is ignored, and it cannot be placed inside a conditional group. @media and @supports, by contrast, act as conditional group rules that wrap ordinary style rules and can be nested.

Tokenization and error recovery

Parsing begins by converting the text into a stream of tokens, such as identifiers, strings, numbers, at-keywords and braces. Comments, written as /* … */, are discarded at this stage and have no effect on the cascade. Malformed text is not allowed to spoil the whole file. When errors occur in CSS, the parser attempts to recover gracefully, throwing away only the minimum amount of content before returning to parsing as normal. The design has a practical motive: new syntax looks like an error to an older parser, and the recovery rules let authors add features without making sheets fail completely in older engines. In practice, if either the property or the value is invalid, that property-value pair is ignored and discarded. An unknown at-rule is skipped up to its terminating semicolon or block, and an unclosed block is closed automatically when the file ends. Parsing and validation are separate steps: after each construct is read, the user agent checks it against the grammar for that construct, and anything that fails the check is treated as if it had never been written. Conformance checkers must report at least one parse error when errors exist, but browsers are free to stop at the first error if they choose not to apply the recovery rules.

Embedding styles and processing order

CSS can reach a document in three main ways: an external sheet loaded through a link element, a style element inside the document, and a style attribute on an individual element. The style attribute holds only the body of a declaration block, without selectors or braces. Within the author origin, the order in which these sources appear matters. Rules from link and style elements are gathered in document order, so when two rules of equal weight conflict, the one that comes later wins. Inline style attributes are applied with a specificity higher than any selector, so they override ordinary selector-based rules unless a stylesheet declaration is marked !important. An @import placed in a sheet is resolved as part of that sheet's order, which is why its position in the file is significant. Because browsers normally wait for stylesheets before rendering, the choice between an external file and an inline block also affects loading performance, a topic taken up elsewhere in this article.

Selectors and specificity

A CSS rule pairs a selector, which states which elements it targets, with a declaration block. Selectors are built from simple parts. A type selector matches an element name such as p, a class selector (.note) matches the class attribute, an ID selector (#header) matches the id attribute, an attribute selector ([href]) tests for an attribute or its value, and the universal selector (*) matches any element. Pseudo-classes such as :hover or :focus-visible match a state of an element that the document tree does not spell out, while pseudo-elements such as ::before or ::first-line address a part of an element or generated content. Because these building blocks can be combined, a single selector can describe a precise position in a document, which is why selector design is closely tied to how HTML documents are structured.

Combinators and structural matching

Combinators connect compound selectors into chains. A descendant combinator (a space) matches any element nested at any depth, the child combinator (`>`) matches only direct children, the general sibling combinator (`~`) matches later siblings, and the adjacent sibling combinator (`+`) matches only the immediately following sibling. Selectors such as ul > li + li therefore express relationships that would otherwise require classes added to markup by hand.

Several functional pseudo-classes extend this structural matching. :is() accepts a selector list and matches any element that fits one of its arguments, which shortens long repeated selectors. :where() accepts the same kind of list with identical matching behaviour, but it contributes no specificity of its own. :has() matches an element according to what it contains or what follows it. For example, a selector that uses :has() can target a figure only when it contains an image. The :has() argument is a relative selector list, so it can begin with a combinator, as in a heading followed by a paragraph. Browser support for these functional forms arrived later than for the basic selectors, and their adoption depended on how each engine implemented the forgiving parsing of selector lists.

How specificity ranks selectors

When more than one declaration targets the same element and property, the browser needs a way to choose between them. The specificity algorithm assigns each selector a weight and compares the weights. In the common formulation the weight is a tuple (a,b,c,d)(a,b,c,d), where aa counts inline style attributes, bb counts ID selectors, cc counts class, attribute and pseudo-class selectors, and dd counts type selectors and pseudo-elements. Universal selectors and combinators add nothing. Comparison proceeds from left to right, so one ID outweighs any number of classes, and the tuple is never summed into a single number. Written as a number for convenience, (0,1,0,0)(0,1,0,0) therefore beats (0,0,99,99)(0,0,99,99). For example, the selector #nav li.active a:hover has the weight (0,1,2,2)(0,1,2,2): one ID, two classes or pseudo-classes (.active and :hover), and two type selectors (li and a).

Two details matter in practice. First, the matching of a functional pseudo-class follows its own rule. :is() takes the weight of its most specific argument, so :is(.card, #featured) p has the weight of its ID argument. :where() always contributes zero, so :where(.card, .panel) p weighs only as much as p. :has() also takes the weight of its most specific argument, so the specificity of a selector using it depends on the content of its argument list. Second, the !important flag and the cascade origin are evaluated before specificity, and cascade layers, which are covered elsewhere in the article, can also override it. Specificity only decides among declarations that remain tied after those earlier steps.

Source order as the tie-breaker

If two declarations have the same origin, importance and layer, and their selectors have the same specificity, the declaration that appears later in the cascade wins. Source order therefore matters only at the final step. Its position in the sheet, or the order in which stylesheets are linked, decides the outcome. This design means that a later rule with a weaker selector can still lose to an earlier rule with a stronger selector, a situation that developers often encounter when styles are scattered across many files. Much of the maintenance difficulty described in the article's later sections stems from this interaction between specificity and order, which led to the use of lower-specificity selectors such as :where() and to the later introduction of mechanisms that separate the cascade into explicit layers.

The cascade, inheritance, and cascade layers

Origins and importance

Each declaration carries a origin that the cascade uses to rank it. The author origin covers styles written by the website developer, the user origin covers styles set in browser settings, and the user agent origin covers the browser's default styles. Operating-system settings and browser extensions also count as user-origin styles. These can come from the operating system level, such as a base font size, or a preference of reduced motion, and they can also come from browser extensions.

Origin is combined with importance. The browser sorts each declaration into one of six buckets, by origin and importance, and there are eight levels of precedence: the six origin buckets, properties that are transitioning, and properties that are animating. Among normal declarations, user-agent styles have the lowest precedence, followed by user styles and then author styles. Important declarations reverse this order, so user-agent !important rules sit at the top of the origin stack, and transitions rank above everything else. Relevance comes first: the cascade finds all declaration blocks whose selectors match each element.

The !important flag was designed to give users some counterweight to authors. CSS attempts to create a balance of power between author and user style sheets. By default, rules in an author's style sheet override those in a user's style sheet. In the 1998 CSS2 specification, user "!important" rules override author "!important" rules. This was a semantic change since CSS1, in which author "!important" rules took precedence over user "!important" rules. In practice, !important is often misused as a quick fix. While it may feel like an easy solution, it often just moves the specificity war from normal to important declarations.

Inheritance and defaulting keywords

Not every property cascades the same way. Inheritable properties, such as color and most font properties, take their value from the parent element when no declaration applies, while most box properties, such as margin, padding, and border, do not. Since colors inherit, a link nested inside another element picks up the inherited color unless a rule overrides it.

Four CSS-wide keywords let authors control this behaviour explicitly. inherit copies the parent's computed value, and initial restores the property's specified default. unset behaves as inherit for inheritable properties and as initial for the rest. revert is the most specific of the four: it rolls the cascaded value back to an earlier origin. For the user origin, it rolls the cascaded value back to the user-agent level, so that the specified value is calculated as if no author-origin or user-origin rules applied to that property on that element.

Cascade layers

Cascade layers, created with the @layer at-rule, add a step to the cascade that is evaluated before specificity. The feature was initially proposed by Miriam Suzanne, a CSS spec author, in 2019. Within each origin and importance bucket, the cascade sorts rules by layer. The layer order for normal declarations runs from the first layer created to the last, followed by unlayered normal styles. This order is inverted for important styles, with unlayered important styles having the lowest precedence.

The practical consequence is that layer precedence always beats selector specificity, and the specificity of a selector in a losing layer is irrelevant. Specificity and source order still resolve conflicts inside one layer. Without an explicit order declaration, layers are ordered by when they are first encountered, which is harder to reason about once CSS is split across multiple files, bundled, or imported in an unpredictable order. Layers may also be nested inside one another.

Scoping with @scope

The @scope at-rule limits where a group of rules can match. It sets a scoping root that determines the upper boundary of the subtree to target, and with a root set, the contained style rules can only select from that limited subtree of the DOM. An optional scoping limit sets a lower boundary, which allows a "donut" scope that excludes a nested sub-component. Inside the block, the :scope selector refers to the scoping root itself.

@scope also adds a cascade criterion called scoping proximity. When two scopes have conflicting styles, the style with the smallest number of hops up the DOM tree to its scope root is applied. This step comes after specificity but before order of appearance. Proximity therefore resolves theme conflicts that would otherwise be decided by source order, while importance, layers, and specificity still take priority over it. Scoping limits the reach of selectors rather than fully isolating a component, so it is not a substitute for Shadow DOM.

Value computation and units

From declared value to actual value

A CSS property does not take effect as soon as it is written. For each property on each element, the browser runs a short pipeline. The cascade first decides which declarations apply, and the result is the specified value. If no declaration applies, an inherited property takes its parent's computed value, and any other property takes its initial value, which is defined in the property's specification. The computed value is reached by resolving relative values as far as possible without laying out the page. For example, an em length becomes an absolute pixel length at this stage, so a padding-top: 2em on an element whose font size is 16px has a computed value of 32px. Computed values are the values that children inherit, which is why a parent's resolved length is passed down rather than the original relative expression.

The used value is determined later, when layout information such as containing-block sizes is available. Percentages are resolved to pixels here, and the used values of dimensions such as width are expressed in pixels. The actual value is the last step: it is the used value after the user agent applies any approximations its environment requires. A browser that can draw only whole-pixel borders, for instance, rounds a fractional border width to an integer. In the CSS 2 model these stages were described as a four-step calculation, and later specifications kept the same vocabulary.

Length units

Length units fall into two families. Absolute units do not depend on other values. The most common is the px, which in CSS is a reference pixel defined relative to the viewing context and not necessarily a single physical device pixel. Other absolute units include centimetres, millimetres, inches, points (1pt equals 1/72 inch) and picas, and they are mainly useful for print. Designers typically use px for fine details such as one-pixel borders, shadows, and small fixed decorations.

Relative units depend on some other reference. em is based on the font size of the element itself for properties such as padding, or on the parent's font size when used for font-size, so nested em values compound. rem (root em) is based on the font size of the root element, which is usually 16px unless the author changes it, and it gives a predictable scale across a page. Percentages are resolved against a property-dependent reference, often the containing block. ch is based on the advance width of the "0" glyph in the current font and is often used to limit line length. Viewport units such as vw and vh are percentages of the viewport's width and height, and vmin and vmax use the smaller or larger of the two. On mobile browsers, where toolbars expand and collapse, the small, large, and dynamic viewport variants (svh, lvh, dvh) describe different visible heights, so 100vh is not always the height a user actually sees. Container query units such as cqi are measured against an ancestor container rather than the viewport and are discussed in the responsive design section.

Math functions and fluid sizing

The functions calc(), min(), max(), and clamp() let a single declaration combine units and compute a result at style-resolution time. calc() supports the four arithmetic operators with the usual precedence and allows mixed units, so a width can be expressed as a percentage minus a fixed offset. In the CSS syntax, the plus and minus operators must be surrounded by spaces. min() selects the smallest of its arguments and max() selects the largest. clamp(MIN, VAL, MAX) is defined as the equivalent of clamp(a,b,c)=max⁡(a,min⁡(b,c))\mathrm{clamp}(a, b, c) = \max(a, \min(b, c)), so the middle value is used unless it falls outside the range set by the two bounds.

These functions are the usual tools for fluid sizing, the practice of letting sizes scale continuously with the viewport instead of jumping at fixed breakpoints. A heading declared as font-size: clamp(1rem, 2vw, 2rem) grows with the window width, never drops below one root-relative unit for readability, and never exceeds a set maximum on very wide screens. Authors use the same pattern for padding, gaps, and container widths, such as width: min(100% - 2rem, 68ch) to keep a text column within both the available space and a comfortable line length.

Custom properties and var()

Custom properties, often called CSS variables, have names that begin with two hyphens and are case-sensitive, so --Brand and --brand are different properties. Their values are stored as raw token streams and are not interpreted until they are substituted into another property through var(). The function accepts a custom property name and an optional fallback, and fallbacks can be nested to form a list of alternatives. Because the spec forbids a custom property from referring to itself, cyclic definitions are invalid.

Unlike preprocessor variables such as those in Sass or Less, custom properties exist in the shipped CSS and are resolved in the browser for each element. They participate in the cascade, respect specificity, source order and !important, and inherit by default from their parent. Their value is computed once per element and the result is what descendants inherit, so a value overridden on a subtree changes every declaration that references it. This runtime behaviour allows values to be changed by media queries, class toggles, or script without regenerating the stylesheet. There are limits, however: var() cannot be used for property names, selectors, or inside media and container query conditions, and browsers cap how far nested substitutions may expand. The @property rule can register a custom property with a syntax, an initial value, and an inheritance flag, which gives authors control that plain declarations lack.

Box model and layout systems

The box model

Every element that CSS lays out becomes one or more rectangular boxes. From the inside out, a box has a content area, padding, a border, and a margin. The content area holds text or child boxes. Padding sits between the content and the border, and an element's background extends through it. The border surrounds the padding. The margin is outside the border and separates the box from its neighbours, and it is transparent.

By default, the declared width and height apply only to the content area. Padding and borders are added on top of that, so the rendered width is Wrendered=w+pL+pR+bL+bRW_{\text{rendered}} = w + p_L + p_R + b_L + b_R, with margins excluded. For example, a box with width: 200px, padding: 20px and border: 5px solid occupies 250 px under the default model. This is the behaviour the box-sizing property controls. If the element has any border or padding, this is then added to the width and height to arrive at the size of the box that's rendered on the screen.

Setting box-sizing: border-box changes the arithmetic. The declared dimension now includes padding and border, so the content area shrinks to make room. The same rule keeps the box at 200 px in the example above. Developers often apply box-sizing: border-box to all elements, including pseudo-elements through a universal selector, which is a common reset in style sheets. Some built-in elements already use this model: tables, selects and buttons, and certain input types such as checkboxes and radio buttons default to border-box. The content area cannot become negative, so border-box cannot make an element collapse entirely.

Display, flow, and formatting contexts

The display property decides how a box takes part in layout. In normal flow, block-level boxes stack vertically, each occupying the full available inline width, while inline-level boxes sit within lines of text and wrap when they run out of space. A block container establishes a block formatting context, in which adjacent vertical margins can collapse and floats are contained. Inline content is laid out in line boxes within an inline formatting context. Certain display values, such as flex and grid, and the flow-root value, establish a new formatting context for their children, which changes how those children are laid out.

Positioning and stacking

The position property offers five schemes. static is the default and keeps the element in normal flow. relative offsets the element from its normal position while keeping the space it originally occupied. absolute removes the element from flow and positions it relative to its nearest positioned ancestor. fixed positions the element relative to the viewport, unless an ancestor has a transform that makes it the containing block. sticky behaves like relative until the element reaches a scroll threshold, then holds its position like fixed within its scrolling container.

Positioned elements, and elements with properties such as opacity below 1 or a transform, can create a stacking context. Within a stacking context, painting order is determined by z-index, and a high z-index value in one context cannot lift an element above a sibling context. Understanding stacking contexts is often necessary to explain why a z-index change appears to have no effect.

Flexbox and Grid

Flexbox arranges items along a single main axis. Its grow, shrink and basis factors distribute free space or absorb overflow, which makes it well suited to toolbars, navigation bars and similar one-dimensional rows or columns.

Grid handles two dimensions at once. It defines a two-dimensional grid-based layout system, optimized for user interface design. Rows and columns are defined as tracks, often sized with the fr unit, and items can be placed into arbitrary cells or spans. Grid became available in major browsers around 2017.

Grid Level 2 adds subgrid. The subgrid value indicates that the grid will adopt the spanned portion of its parent grid in that axis. A nested grid therefore uses the parent's tracks, so its items can align with the outer layout even several levels deep. Subgrid was originally part of Grid Level 1, but the working group moved it to Level 2 in 2017 because of its complexity. At that time no browser had implemented it, and it became widely usable only in later years.

Responsive design and media queries

Responsive design is the practice of building one style sheet and one document so that the layout adapts to the space and capabilities of the device showing it. CSS supplies most of the mechanisms for this. The main tools are conditional rules that test the environment, flexible units that let sizes scale, and, more recently, conditions that test the size of an individual component rather than the whole window.

Media queries

The @media rule attaches styles to conditions about the output device. Its features include viewport width and height, orientation, aspect ratio, display resolution, and user preferences such as prefers-color-scheme, prefers-reduced-motion, and prefers-contrast. Early queries relied on CSS3 media queries, which were close to practical use around 2008 and 2009, and the older min- and max- prefixes are still common. The newer syntax comes from Media Queries Level 4, which allows comparisons in a range context, so that a condition can be written with ordinary operators instead of prefixes. The specification also states that media features accept only single values, so a complex calculation cannot be passed as a test value.

The preference features are defined in Media Queries Level 5. The feature is defined in CSS Media Queries Level 5, and sources disagree on its current value list. Some describe a third value, no-preference, alongside light and dark, while another note states that a third option no-preference was recently removed from the specifications due to lack of implementations. Authors should therefore treat light as the fallback unless they check the current specification.

Container queries

Container queries apply the same kind of conditional logic to the size of an ancestor element. The @container at-rule enables applying styles to elements based on a containing element's size or other features, rather than the viewport's. This matters for components such as cards, navigation bars, or widgets that may appear in a wide main column or a narrow sidebar. A component that responds to its own container can be reused in both places without a separate class for each context.

An element becomes a query container only when it is declared as one. Elements are declared as size query containers by setting their container-type property (or the container shorthand) to size or inline-size. The inline-size value tests only the width in a horizontal writing mode, which covers most responsive cases, while size also tests height. The trade-off is that this containment limits how the container's own size depends on its children, so a container cannot simply shrink to fit content it is supposed to measure. Named containers, given through container-name, let a query target a specific ancestor when several are nested. Container style queries are a separate feature that tests the computed value of a custom property or another declaration on an ancestor.

Container queries also add relative length units such as cqw and cqi, which measure a fraction of the container's size rather than the viewport. Support arrived later than for media queries. Browsers first shipped size queries and extended them afterwards, and the feature reached Baseline Widely Available status in 2024, according to one guide. Some older articles still report missing support in Safari and Firefox, so compatibility should be checked against current data for the target audience.

Fluid layouts and relative units

Media queries work best alongside layouts that stretch smoothly rather than jumping between fixed sizes. Percentages, em and rem units, viewport units such as vw and vh, and the functions min(), max(), and clamp() let a value grow and shrink between limits. A heading might use a font size that scales with the viewport but never falls below a readable minimum or rises above a set maximum. Flexbox and Grid, described in other sections, supply the layout structure that makes these values useful.

Ethan Marcotte gave the approach its name in a May 2010 article in A List Apart, where he drew an analogy with responsive architecture and described three techniques: flexible grids, flexible images, and CSS media queries. The ideas had appeared earlier. The technique of adaptive web design predates Marcotte's first use of the term responsive web design. Mobile-first design and progressive enhancement were also established before the term existed.

Reduced reliance on scripting

Before these features matured, developers often detected the screen width or device type with JavaScript and then loaded or rearranged markup. Those scripts were fragile, added to page load, and were easy to get wrong when the browser window was resized or when a device reported unusual dimensions. Declarative conditions in CSS moved much of this logic into the style sheet, where the browser can evaluate it during layout without running application code. JavaScript remains necessary for behaviour such as changing the document structure, but the visual adaptation of a page now mostly happens in CSS.

Color, typography, and visual styling

Color models and color-mix()

Early CSS colors were written as keywords, hexadecimal codes, or the sRGB-based rgb() and hsl() functions. Those models do not change evenly as perceived brightness changes, so a midpoint between two colors often looks dull. Newer spaces address this. Oklab is a color space published in the W3C's CSS Color series by the CSS Working Group, and its predecessor was CIELAB. Modern CSS also provides wide-gamut access through color(display-p3 …), which reaches colors beyond sRGB.

The color-space-aware <code>color-mix()</code> function blends two colors. Its <code>in</code> keyword names the space in which the mix happens. If no space is named, the default is oklab, and polar spaces can also take a hue-interpolation method, which defaults to the shorter hue. Some popular guides say the default is oklch, so authors should check the specification rather than rely on secondhand claims. The choice matters: mixing in oklch preserves perceptual uniformity, while mixing in srgb can produce muddy mid-tones, especially for complementary colors. Because the result is computed at runtime, a single custom property can drive a whole tint-and-shade scale, which is why the function is often described as replacing the Sass color functions such as lighten() and mix().

Fonts, font loading, and text

Custom typefaces are declared with the <code>@font-face</code> rule, which maps a family name to one or more font files and descriptors such as <code>font-weight</code>, <code>font-style</code>, and <code>unicode-range</code>. The rule lets a font family be split into a collection of separate resources, so a page does not have to download a single file that contains every variant.

The <code>font-display</code> descriptor controls what readers see while a face is loading. Its values are auto, block, swap, fallback, and optional. A block value gives a short invisible period, commonly about three seconds, followed by an unlimited swap period, while swap uses a very short block period and then swaps in the web font whenever it arrives. With optional, the browser may decline to swap the font at all if it is not ready in time. These options trade off the "flash of invisible text" against the "flash of unstyled text" that occurs when a fallback is replaced, and therefore against layout shift.

Font metrics, such as ascent and descent, differ between a web font and its fallback, which is a common cause of layout shift. Proposals in the CSS Fonts Module Level 5 would add descriptors such as <code>ascent-override</code>, <code>descent-override</code>, and <code>line-gap-override</code> so that fallbacks can be tuned to match. One related descriptor, advance-override, has since been dropped from the proposal. Text properties such as <code>line-height</code>, <code>letter-spacing</code>, and the newer <code>text-wrap</code> values (balance and pretty) control how lines break and how dense a paragraph looks. Their behavior interacts with the <code>Unicode</code> text being rendered and with the font's own metrics.

Backgrounds, borders, shadows, gradients, and images

A single element can carry several background layers, each with its own image, size, position, and clipping area. Borders can be rounded, and they can be filled with an image through <code>border-image</code>. Box shadows take offset, blur, spread, and inset parameters, which make them useful for depth cues without extra markup. Gradients (linear, radial, and conic) are themselves images, so they can be used in <code>background-image</code> or <code>mask-image</code>. Since CSS Images Level 4, gradients also accept an interpolation space: a linear gradient can be defined to run "in" a named color space such as oklab, rather than the default sRGB. Images, whether raster or vector, can be sized and cropped with <code>object-fit</code> and <code>background-size</code>.

Filters, blend modes, and transforms

CSS filter functions, such as blur, brightness, contrast, grayscale, and drop-shadow, transform the rendered pixels of an element. <code>backdrop-filter</code> is different: instead of altering the element's own content, it applies filters to whatever lies behind the element. This is the basis of the frosted-glass effect.

The <code>mix-blend-mode</code> property determines how an element's pixels combine with the backdrop inside the same stacking context. Its keyword values include multiply, screen, overlay, darken, lighten, difference, exclusion, and the hue, saturation, color, and luminosity modes, which are taken from image editing. The property sets how an element's content should blend with its backdrop, that is, the content rendered behind it within the same stacking context. Combining the two effects has limits: in one practitioner's testing, when mix-blend-mode is used, the blur from backdrop-filter is lost.

The rendering cost is significant. Filters and opacity create stacking contexts, and a backdrop filter must in principle see everything painted before it. Each use of backdrop-filter or mix-blend-mode can require a separate rendering pass, which may double the rendering time and increase memory and GPU bandwidth needs. The W3C's Backdrop Root proposal and the Filter Effects Level 2 draft address this by defining a boundary that limits how far backward these effects reach. In practice, engines accelerate backdrop filters on the GPU, but authors are still advised to avoid them on elements that animate or scroll over other content at high frequency.

Transitions, animation, and interactivity

CSS offers three families of motion: transitions that bridge two computed states, keyframe animations that run a sequence of states, and newer mechanisms that drive progress from scroll position or from a change in DOM state. Together they let designers add motion to HTML pages without scripting a frame loop, although JavaScript still triggers many of them.

Transitions

A transition interpolates a property from its old value to its new value when a style change occurs, instead of jumping instantly. Four longhand properties govern it. The transition-property property names the properties to animate, transition-duration sets how long the change takes, transition-delay postpones the start, and transition-timing-function shapes the pace. Some older tutorials state that CSS will transition your elements at a constant speed by default, but the specification's initial value for the timing function is ease.

Timing functions are sometimes called easing functions. Keywords include ease, linear, ease-in, ease-out, ease-in-out, step-start, and step-end, while cubic Bézier curves and stepping functions allow custom curves. The formal definitions live in a separate module, and the input progress value used is the percentage of the transition duration, which the output of the timing function then reshapes before the property is interpolated.

Transitions have some subtle rules. A running transition keeps its original timing settings even if those values change mid-flight, but if the transition-property property changes such that the transition would not have started, the transition stops and the property jumps to its final value. When a property appears more than once in the list, the last matching entry supplies the timing.

Keyframe animations

Transitions connect only two states, so they cannot express multi-step motion. The @keyframes rule defines a sequence of intermediate states at keywords such as from and to or at percentage stops. A spinning element, for example, can be specified with a keyframe that rotates from transform: rotate(0deg) to a full turn. The animation is then attached to an element through the animation shorthand or its longhands, which control the name, duration, timing function, delay, iteration count, direction, fill mode, and play state. Because keyframes are reusable, the same definition can drive many elements.

Scroll-driven animations

Ordinary animations advance with elapsed time. Scroll-driven animations replace the clock with a scroll position. The feature is controlled by the animation-timeline property, which was introduced as part of the CSS Animations Level 2 spec in June 2023, according to WebKit's guide. Two timeline types are common. A scroll progress timeline, written as scroll(), follows the scroll progress of a scroll container, while a view progress timeline, written as view(), follows an element's own visibility within the scroll container.

With a scroll timeline, the animation's start and end correspond to the scroll limits. At 0% scroll the animation is at its from keyframe; at 100% scroll it is at its to keyframe. A duration is therefore unnecessary, and any animation-duration you set is ignored in that case. The animation-range property restricts the portion of scrolling that drives the animation; in one example, specifying a range of 0 80px makes the animation finish after 80 pixels of scrolling. View timelines accept arguments as well. The value view(20% block) starts the animation when the image is 20% visible in the scrollport. For cases where the scroller is not an ancestor of the animated element, named timelines declared with scroll-timeline-name and scoped with timeline-scope connect the two. The Scroll-driven Animations module was still published as an editor's draft in 2026, so its syntax may change.

The View Transitions API

Animating a change between two DOM states is difficult with ordinary CSS, and page navigations are the hardest case. The View Transitions API addresses this by letting the browser capture the old and new states. A same-document transition is started with document.startViewTransition(), and when we call the startViewTransition function, the API takes a screenshot of the old page state and performs the DOM update. The new live state is then captured, and what we see during the transition is generated by the CSS and not the actual DOM elements.

The browser builds a pseudo-element tree rooted at ::view-transition, and the default animation is a cross-fade. The old snapshot appears as ::view-transition-old(root) and the new one as ::view-transition-new(root), so developers can restyle the timing or the visuals with ordinary animation rules. For individual elements, a view-transition-name assigned in CSS lets an element be matched across the two states, so that its position and size interpolate between them. Cross-document transitions between separate pages are enabled with an @view-transition rule that sets navigation to auto. The API is described by the CSS View Transitions Module Level 1 and Level 2 drafts, which cover the cross-document case.

Because the transition is composed from snapshots, developers should still respect user preferences. Several sources recommend a prefers-reduced-motion override alongside the feature, and browser support has changed over time, so the current compatibility status should be checked against the baseline data rather than older articles.

Print, accessibility, and user preferences

Paged media and printing

CSS was first designed for "continuous" media, such as scrolling web pages. By contrast, "paged" media have page breaks that split up the HTML document, as with PDFs, books, catalogs, and presentations. The paged-media features address this gap. In CSS 2.1, the size of a page box cannot be specified, although authors could set its margins inside an @page block. Size control, page-margin boxes, and named pages were later defined in the separate Paged Media module, which is a set of CSS properties defined in the W3C CSS Paged Media Module Level 3 specification.

Page breaks are governed by properties such as break-before, break-after, and break-inside, together with orphans and widows, which control how many lines must remain together at the top or bottom of a page. Browser support was uneven for a long time. One report noted that the paged-media and generated-content specifications have been stuck in W3C draft status and have been barely implemented by browsers. More recent guides list @page as available in current Chrome and Safari releases and partial in Firefox, while margin boxes were then limited to Chrome.

Media types

Media types were the earlier mechanism for tailoring a style sheet to an output device. CSS2 defines the same list, deprecates 'aural' and adds 'embossed' and 'speech'. The print type is intended for paged material and for documents viewed on screen in print preview mode. The speech type is intended for speech synthesizers.

The speech story is one of unfulfilled intent. Aural style sheets appeared in CSS2 in 1998, but CSS 2.1 in 2011 deprecated the 'aural' media type and introduced the reserved 'speech' media type (but didn't specify its behavior). The later CSS Speech module was designed to be compatible with the Speech Synthesis Markup Language (SSML), W3C's language for controlling speech synthesizers. In practice, a compatibility test by PowerMapper reported that @media speech is deprecated in CSS Media Queries Level 4 and not supported by any screen reader. Screen-reader users therefore cannot rely on this media type.

Preference queries

Preference media features let a stylesheet respond to settings chosen in the operating system or browser. The prefers-reduced-motion feature indicates if the user has requested to minimize the amount of motion on a page. Because a reduced-motion rule placed later in the source with the same specificity takes precedence, authors can swap a pulsing animation for a gentler one if the user enables the setting for reducing motion.

The prefers-color-scheme feature detects whether a user has requested a dark or light theme. Combined with custom properties, this allows a single set of variables to switch a site's palette. Support is broad: one accessibility review noted high browser support — 96% (as of the second half of 2024). Related features such as forced-colors matter for users of high-contrast modes, because author colours, backgrounds and shadows are replaced by system colours, so information carried only by colour or background images can disappear.

Accessibility concerns

Accessibility guidance treats adequate contrast, visible focus, understandable status, and controls that remain operable as baseline requirements for any presentation, not optional refinements. Removing the default focus outline without providing a replacement makes keyboard navigation difficult, and low-contrast text fails users with low vision. Formal benchmarks such as the WCAG guidelines set minimum contrast ratios for text, commonly 4.5:1 for body text at the AA level.

CSS can also hide content from some assistive technologies. Declarations such as display: none remove an element from the accessibility tree, and visibility: hidden has a similar effect, so screen readers skip that content. Visually hidden techniques keep text available to assistive technology while hiding it from sighted users. Designers must therefore check that content revealed or concealed by CSS still makes sense in HTML structure and in scripted interactions. These concerns connect the print and preference features to broader disability access.

Tooling, preprocessors, and methodologies

Preprocessors

Preprocessors were the first major answer to the repetition that large hand-written style sheets produce. Sass, short for Syntactically Awesome Stylesheets, was released in 2006 and was written in Ruby. Less, or "Leaner Style Sheets," followed in 2009, created by Alexis Sellier. Both add variables, nesting, and mixins, and both compile their input into ordinary CSS. As one overview puts it, the preprocessor compiles the code into standard CSS that browsers can understand. The two tools also influenced each other. The newer SCSS syntax of Sass was inspired by the syntax of Less. Syntax differs in small ways: in Sass, variables are defined using the "$" symbol, while in Less, they are defined using the "@" symbol.

Sass also offered features beyond variables and nesting, such as control directives and functions. Several of the ideas it popularized, including custom properties and native nesting, were later absorbed into CSS itself, which reduced the need for a separate compile step in some projects.

Post-processors and build pipelines

A post-processor works on CSS that is already valid. PostCSS is not a preprocessor, although it can behave like one. It is a Node.js tool which takes valid CSS and enhances it. Its design is modular: users can compose a set of plugins to create a customized PostCSS processing pipeline. The most common plugin is Autoprefixer, which automatically prepends -webkit, -moz, and -ms vendor prefixes to CSS properties which require them. It relies on browser-usage and feature-support data, so it parses CSS and adds vendor prefixes using values from Can I Use. Prefixing has limits: it cannot supply a property a browser lacks altogether. Minification is handled by plugins such as cssnano, which reduces the CSS file in size by removing whitespace and redundant code.

Order matters in these pipelines. One guide notes that the order of plugins is important: postcss-easy-import should be always first, and autoprefixer should be the last plugin on the list. Bundlers such as Vite, Webpack, and Rollup usually run these steps in a fixed sequence after compilation, though the exact order depends on the plugins in use.

Naming methodologies

Because the cascade is global, teams have developed conventions to keep class names predictable. BEM (Block, Element, Modifier) is the best known. BEM methodology was first introduced by Yandex in 2010. A block is a standalone component, an element is a part of a block that has no meaning on its own, and a modifier is a variant of either. In practice this yields names such as block__element--modifier, with elements separated from blocks by two underscores and modifiers separated by two hyphens. BEM's aim is to keep selectors flat: one goal of BEM is for most selectors to use just a single class name. The cost is verbosity in both HTML and CSS. BEM is a naming discipline rather than a tool, so it can be used with plain CSS, Sass, or Less alike.

Utility-first frameworks such as Tailwind CSS take the opposite approach. They supply many small, single-purpose classes that are applied directly in markup, so authors rarely invent component-specific names. This reduces stylesheet growth and naming decisions, but markup becomes dense, and reuse moves into component templates or abstractions. CSS-in-JS libraries go further by writing styles in JavaScript and attaching them to components, which gives automatic scoping and makes dynamic styles driven by props straightforward. The trade-off is runtime cost in the browser and added bundle size, along with extra complexity when rendering on the server.

Trade-offs

No approach dominates. Preprocessors and build tools improve reuse and tooling but add a compile step and configuration. Naming conventions such as BEM improve readability and keep specificity low, but depend on team discipline. Utility-first and CSS-in-JS approaches can speed up development and keep styles close to their components, yet they shift complexity into markup or runtime code. Teams therefore weigh maintainability, page performance, and how their members collaborate, and many combine approaches, for example a utility framework with a PostCSS pipeline.

Browser implementation and rendering

When a browser loads a page, it turns the HTML into the Document Object Model and turns every stylesheet, whether linked, embedded, or inline, into the CSS Object Model (CSSOM). Engines differ in their code: Blink and WebKit name their parser "CSSParser," while Gecko uses Mozilla's Stylo parser, a Rust-based component shared with Servo. The CSS parser, literally named "CSSParser" in Blink and WebKit while Gecko uses Servo's CSS parser called "Stylo", reads stylesheets and produces the CSSOM. The CSSOM is a structured representation of rules, selectors, and declarations, and scripts can read it through interfaces such as document.styleSheets and computed-style APIs. Style resolution is the step that then matches selectors against elements, applies the cascade and inheritance, and produces a computed value for each property on each element.

The rendering pipeline then runs in stages. The DOM and CSSOM are combined into a render tree, which omits nodes that are not displayed, such as those with <code>display: none</code>. After the render tree is complete, layout occurs, defining the location and size of all the render tree elements. Paint then fills pixels for boxes, text, images, and borders, and compositing merges separately painted layers on the GPU into the final frame. Changes to the DOM, to class names, or to inline styles can invalidate part of this work. A script that changes a style and then reads a layout property can force the engine to recalculate layout synchronously, which is why performance guidance tends to separate reads from writes.

Because the CSSOM is built as a whole rather than incrementally, it also affects load time. CSS is render blocking: the browser blocks page rendering until it receives and processes all the CSS. CSS is render blocking because rules can be overwritten, so the content can't be rendered until the CSSOM is complete. A single slow stylesheet can therefore delay the first paint of an entire page, which is the reason for practices such as inlining critical CSS, discussed elsewhere in this entry.

Vendor prefixes were a workaround for the period when features were drafted but not yet interoperable. The CSS 2.1 specification introduced a policy under which each engine marked experimental properties with its own string, such as -webkit-, -moz-, -ms-, or -o-. Because each prefixed name is treated as a separate property, browsers ignore prefixes they do not recognize, which let implementers test ideas without colliding with the eventual standard name. Authors commonly listed the prefixed declarations first and the unprefixed one last, relying on the cascade so that the standard version would win once supported. In practice, prefixes lingered. Sites frequently used just the prefixed version of a feature, which made it hard for browsers to drop support for the prefixed variant when adding support for the unprefixed, standard version. This pressure pushed engines to implement one another's prefixes, which fragmented the ecosystem further. Some of the decline came from engine consolidation: In 2019, Edge switched from its own rendering engine to Blink. Overall, the number of features that require prefixing fell by ~33% between 2013 and 2021. Build tools such as Autoprefixer now add the required prefixes automatically, and browser vendors increasingly prefer feature flags for experiments.

Feature support is now tracked through shared compatibility labels rather than version tables alone. Web Platform Baseline classifies features by their availability across a fixed set of browser and platform combinations, which the MDN documentation lists as Safari on iOS and macOS, Chrome on Android and desktop, Edge on desktop, and Firefox on Android and desktop. A feature is "newly available" once all of these support it, and it becomes "widely available" after 30 months have passed since the newly interoperable date. Features missing from any browser in the set have limited availability. The label has limits: it does not cover older devices, operating-system web views, or assistive technologies such as screen readers, so it is a summary rather than a substitute for testing.

On the authoring side, feature queries let style sheets adapt to the engine at hand. The @supports rule applies a block of declarations only when the browser understands a given property or value, which allows newer layout or color features to be used with fallbacks in older engines. Combined with Baseline data, this lets developers choose which features to rely on directly and which to wrap in progressive enhancement.

Relations with HTML, the DOM, and JavaScript

Linking styles to markup

CSS was built to style structured documents rather than one particular markup language. Its specification describes the language as a way of rendering structured documents such as HTML and XML on screens, on paper, and in other media CSS is a language for describing the rendering of structured documents (such as HTML and XML) on screen, on paper, etc.. The styling engine never works on the raw source text. It works on the document tree exposed through the Document Object Model, matching selectors against nodes and then assigning values to each element. The same separation applies to XML, where a stylesheet can be associated with a document through a separate standard for XML style-sheet association, which the CSS Object Model specification itself references This specification employs certain terminology from the following documents: DOM, HTML, CSS Syntax, Encoding, URL, Fetch, Associating Style Sheets with XML documents and XML.. The mechanics of attaching styles, such as link and style elements and inline attributes, are covered in the syntax section.

The CSS Object Model and scripts

The CSS Object Model (CSSOM) is the set of interfaces that lets scripts read and change style information. It is conceptually the styling counterpart of the DOM. Where the DOM lets JavaScript inspect and alter a document's structure and content, the CSSOM gives the same kind of access to its styling similar to the way in which the DOM enables a document's structure and content to be read and modified from JavaScript, the CSSOM allows the document's styling to be read and modified from JavaScript.. The interfaces originated in the DOM Level 2 Style recommendation and were later split out into their own specification, which is designed to supersede that earlier work Initially defined in the DOM Level 2 Style recommendation, these interfaces forms now a specification, CSS Object Model (CSSOM) which aims at superseding it..

Two kinds of access are relevant to authors. The first is editing the stylesheet itself: CSSOM objects expose rules and their selectors, and methods such as insertRule let a script add a rule to a sheet at runtime Those interfaces contain members like insertRule, selectorText, and parentStyleSheet for accessing and manipulating the individual style rules that make up a CSS stylesheet.. Such changes affect the browser's internal representation, not the file on the server, which is a point that is easy to forget as with individual element's DOM styles, when speaking of manipulating the stylesheets, this is not actually manipulating the physical document(s), but merely the internal representation of the document..

The second kind of access is reading the result of the cascade. The method getComputedStyle returns a live, read-only object describing the values of an element's properties after the active stylesheets have been applied The Window.getComputedStyle() method returns a live read-only CSSStyleProperties object containing the resolved values of all CSS properties of an element, after applying active stylesheets and resolving any computation those values may contain.. These are resolved values, not the specified declarations. A width given as a percentage or as auto, for example, is reported as an absolute pixel length While the three specified values, auto, 50%, and inherit, are keyword and percentage values, retrieving the width using window.getComputedStyle(el)["width"]; returns an absolute length px value. The read-only design is intentional: the documentation recommends reading through getComputedStyle and writing through the element's own style object The object from getComputedStyle is read-only, and should be used to inspect the element's style — including those set by a element or an external stylesheet. The element.style object should be used to set styles on that element, or inspect styles directly added to it from JavaScript manipulation or the global style attribute.. The distinction matters because the computed object includes inherited values, while the element's own style object does not Note that the inline styles only include the styles defined on the actual element: all the other properties have the value "" and are not displayed. The computed styles also include font-weight, which is defined on the parent, and many other computed styles..

Performance is a practical consequence of this coupling. Browsers process the CSSOM before they apply style changes made by scripts, and layout, paint, and compositing are repeated for each script-driven style update Browsers parse the CSSOM — including layout, paint, and composite processes — before applying any style updates found in scripts. In addition, layout, paint, and composite processes are repeated for JavaScript style updates.. Authors therefore tend to batch changes, or to switch classes instead of setting many inline values one by one. This is a general inference from the pipeline, not a claim from a specific source.

Custom properties as a bridge

Custom properties are the most convenient point where scripts and stylesheets meet. Because a custom property is an ordinary declaration that takes part in the cascade and inheritance, a script can set it on a container, and every rule that reads it through var() will update without the script needing to know those rules. The CSS Properties and Values API extends this idea by letting a property be registered with a type, an initial value, and an inheritance flag Properties registered using this API are provided with a parse syntax that defines a type, inheritance behavior, and an initial value.. A typical registration looks like this in JavaScript: a call to CSS.registerProperty with a name, a syntax string, an inherits flag, and an initialValue. The same definition can also be written in CSS with an @property rule. Typed registration matters for animation, because the browser cannot interpolate an untyped string. One source notes that the main selling point of the API is that developers can animate custom properties, which is not possible with current technology alone. If a script assigns a value of the wrong type, the browser discards it and uses the default If you assign a value of the wrong type to a variable, the browser will ignore it and choose the default value..

Houdini-style APIs

CSS Houdini is the umbrella name for a group of low-level APIs that expose parts of the style and layout machinery. In the words of the MDN documentation, Houdini is a set of low-level APIs that exposes parts of the CSS engine, giving developers the power to extend CSS by hooking into the styling and layout process of a browser's rendering engine.. The goal is to let authors write code that the browser treats as CSS, so that new behaviour does not have to wait for native implementation Houdini is a group of APIs that give developers direct access to the CSS Object Model (CSSOM), enabling developers to write code the browser can parse as CSS, thereby creating new CSS features without waiting for them to be implemented natively in browsers..

The main pieces are the following. The Properties and Values API covers registration of typed custom properties, described above. The Typed OM addresses the cost of string handling: Converting CSSOM value strings into meaningfully typed JavaScript representations and back can incur a significant performance overhead. The CSS Typed OM exposes CSS values as typed JavaScript objects to allow their performant manipulation.. The Painting API lets a script draw into a box's background, border, or content, and is invoked through the paint() function in a CSS value Developed to improve the extensibility of CSS, the Painting API allows developers to write JavaScript functions that can draw directly into an element's background, border, or content via the paint() CSS function.. A paint worklet declares which custom or standard properties it needs through an inputProperties list, and its paint method then reads their values from a third argument We've added inputProperties to tell the paint worklet which CSS properties to look for. After that, the paint() function can use a third incoming parameter, props, to access the values for these properties.. The higher-level APIs are the Paint, Layout, and Animation APIs, which interact with the rendering engine directly High-level APIs interact with the CSS rendering engine. They consist of the Paint, the Layout, and Animation API..

These APIs are not uniformly available. Their specifications have progressed at different speeds, and support in each engine should be checked against current compatibility data before a Houdini feature is relied on in production.

Performance, maintenance, and criticism

Render blocking and loading cost

Browsers treat stylesheets as blocking by default. The browser will not paint anything until every stylesheet is downloaded and parsed. The cost is largest for the external stylesheets in the document head. A stylesheet whose media query does not match the current device is fetched at lower priority and does not hold up rendering, which is why authors use media attributes to separate print or large-screen rules from the rest.

Optimization work usually follows from this. Critical CSS, meaning the rules needed for the above-the-fold region of the page, is extracted and placed inline in the head, while the remaining rules are loaded later. Inlining that CSS in the page's head tag, then deferring the non-critical CSS is the usual sequence. Some practitioners recommend keeping the inlined block small enough to fit within the roughly 14 KB that a TCP connection's initial congestion window typically delivers in its first round trip, so the first paint can happen after a single round trip. Coverage tooling in browser developer tools helps identify which rules are actually used during first render, and extraction libraries such as Filament Group's Critical automate the process. Unused rules also cost bandwidth and parse time, so build-time pruning is common.

Critics note that CSS is only one part of the problem. Synchronous JavaScript in the head also blocks rendering, so moving CSS out of the critical path may have no effect on start-render time if a script is the actual bottleneck. Tuning CSS delivery therefore has to be considered together with the loading order of scripts.

Global scope and the specificity problem

Almost every criticism of large CSS codebases starts from the fact that all CSS selectors are global, matching against the entire DOM. A rule written for one component can silently affect unrelated parts of a page, and a selector can lose out in the global specificity war, ultimately having little or no effect on the page at all. Authors respond by writing ever more specific selectors, which in turn makes later overrides harder, a pattern often called specificity escalation.

The methods developed in response are mostly conventions and tooling. Naming schemes such as OOCSS, SMACSS, BEM, and SUIT give each component a prefix so that class names rarely collide. BEM in particular keeps every selector at a single class, which creates some kind of scope for your components and keeps specificity low. Its costs are practical: naming too many things is frustrating, and class names grow long as a project evolves. Build-tool approaches such as CSS Modules take a different route by generating unique class names during bundling, which removes collisions between files but adds a build dependency and makes runtime class names harder to read in developer tools.

Debates over nesting and layers

The introduction of native features has produced disagreement about whether they reduce or add complexity. Cascade layers were designed largely to address specificity escalation. Before them, developers often added selectors adding more IDs, classes, or nesting to override styles from frameworks or third-party libraries. Layers make the priority of whole groups of rules explicit, and the ordering is fixed by the sequence in which layers first appear, not by the selectors inside them.

Native nesting has been contested in a similar way. Some commentators argue that nesting inherently escalates specificity, potentially causing unintended style overrides and conflicts within the cascade. Others argue that nesting is a useful way to organize code, and that it still leaves the underlying problem in place. One critic has written that CSS calculates priority based on the type of selectors, not their intent, so nesting does not address the core issue. Guidance from practitioners generally favors shallow nesting, on the grounds that deep nesting adds complexity without much benefit.

The scoping proposals show a similar tension. An earlier scope specification was never implemented. The later @scope rule takes a structural approach, and its scoping does not depend on specificity, so a rule outside a scope with higher specificity can still win. Whether such structural scoping is an improvement over naming conventions remains a matter of preference, especially for teams whose existing tooling already works well.

Standardization and uneven adoption

Standardization does not guarantee that every browser ships a feature at the same time. The @scope rule, for example, became available in Chrome 118 and Safari 17.4 at different points, and similar gaps have appeared with many other modern features. Authors who depend on newer capabilities must therefore use feature queries, fallbacks, or progressive enhancement, and must account for the time it takes for older browser versions to disappear from real traffic. This gap between the specification and the installed base is one reason that CSS, despite its declarative design, remains difficult to maintain across large projects.

Future directions and open problems

Native functions and mixins

The most discussed gap is reusable logic in plain CSS. The Working Group resolved to adopt a proposal for custom functions and mixins in early 2024, and a draft followed in mid-2024. Functions return CSS values that can only be used inside a property's value. Mixins return declarations or whole rule blocks and can only be used outside a property's value. A function is declared with @function and takes parameters. Mixins are called through a new @apply rule, which is different from Sass's @include. The draft also requires names that begin with two hyphens, which keeps custom names from colliding with built-in functions.

The draft has changed as it developed. At one point the spec described custom functions only, and open questions remain, such as named argument passing and whether the result should be mandatory in @function.

Native features could reduce the need for preprocessors such as Sass. Custom properties and nesting have already reduced reliance on preprocessors, but looping and reusable logic still often feel necessary to reach for a preprocessor. Sass maintainers have planned their own compatibility steps, including deprecating function and mixin names that begin with a double hyphen so that native syntax does not clash with Sass code.

Anchor positioning and other layout work

Anchor positioning is a native browser mechanism that lets you position elements relative to other elements without scripting. An anchor is marked with anchor-name, and the positioned element refers to it through position-anchor and the anchor() function. position-try-fallbacks lets the browser choose alternative placements when the primary position overflows.

Browser support reports disagree. One source states that it shipped in Chrome 125 in May 2024, while another says that in January 2026 it officially attained Baseline Newly Available status after Firefox enabled it. A later article states that Firefox is still implementing it as of August 2026, and a separate article notes that the Web Platform Baseline still labels it as not yet Baseline. These sources are secondary blogs with differing dates, so current status should be checked against official browser release notes and the specification itself. Spec maintainers have also flagged remaining gaps.

Beyond anchor positioning, the sources consulted here do not describe the remaining gaps in native layout control in detail, so this section does not enumerate them.

Cascade, scoping and color

Scoping is one of the most active areas. The Cascading and Inheritance Level 6 draft introduces the @scope rule, which limits selector matching to a bounded region. Earlier, an old scope specification was never implemented, and focus moved to Shadow DOM, which is mainly concerned with full isolation. The scoping proposal aims at a lighter approach, and one draft suggested that scope proximity should rank after selector specificity but before source order.

Cascade layers have also needed refinement. Cascade Level 5 introduces layers as a structured way to organise concerns within a single origin. In 2021 the Working Group changed the earlier decision so that unlayered styles come last in the layer order.

On colour, Color Level 4 extends the range of color spaces beyond sRGB, and further colour-space and gradient work continues in later drafts.

Standards process and compatibility

Annual snapshots now define the stable state of the language. The 2026 snapshot is a single definition collecting the modules that together form the state of CSS as of 2026, and it is published annually rather than as a draft.

The central tension is compatibility. Because CSS is used by an enormous number of existing documents, new syntax must not break older content. Authors typically handle this with feature detection using @supports and JavaScript-based fallbacks while support is still spreading. Prefixed or dashed names, deprecation cycles in tools such as Sass, and annual snapshots are all mechanisms for introducing features without invalidating existing style sheets, though each adds complexity for implementers and authors.

References

  1. Håkon Wium Lie, the Creator of CSS, at Codemotion Milancodemotion.com
  2. A brief history of CSS until 2016w3.org
  3. History of CSSsitesbay.com
  4. A Brief History of CSSshecodes.io
  5. W3C PR-CSS1-961112w3.org
  6. 201: Levels of CSSrussmaxdesign.github.io
  7. W3C Issues CSS2 as a Proposed Recommendationw3.org
  8. The World Wide Web Consortium Issues CSS2 as a W3C Recommendationw3.org
  9. REC-CSS2-19980512 Cascading Style Sheets, level 2 CSS2 Specificationw3.org
  10. REC CSS1 20080411w3.org
  11. Cascading Style Sheet (CSS) File Formatloc.gov
  12. CSS current work & how to participatew3.org
  13. W3C Process Documentw3.org
  14. CSS Snapshot 2025w3.org
  15. CSS Working Group Charterw3c.github.io
  16. WD css beijing 20071019w3.org
  17. CSS Snapshot 2018w3.org
  18. CSS Snapshot 2023w3.org
  19. CSS Snapshot 2020w3.org
  20. CSS Snapshot 2026w3.org
  21. Publicationsw3.org
  22. CSS Syntax Module Level 3w3.org
  23. At-rules - CSS - MDN Web Docsdeveloper.mozilla.org
  24. CSS error handling - MDN Web Docsdeveloper.mozilla.org
  25. CSS Syntax Module Level 3w3.org
  26. CSS @import Rulew3docs.com
  27. Introduction to CSS syntax: declarations, rulesets, and statements - CSSdeveloper.mozilla.org
  28. The Quick Guide to CSS Specificity - Slicejackslicejack.com
  29. Specificity - CSS - MDN Web Docsdeveloper.mozilla.org
  30. :is() vs. :where()gomakethings.com
  31. where() CSS pseudo-class - MDN Web Docsdeveloper.mozilla.org
  32. Selector list - CSS - MDN Web Docsdeveloper.mozilla.org
  33. :wherecss-tricks.com
  34. Specifics on CSS Specificitycss-tricks.com
  35. Screencast: Origin and Importance in the CSS Cascade — SitePointsitepoint.com
  36. The cascade - CSSweb.dev
  37. Cascade layers - Learn web developmentdeveloper.mozilla.org
  38. 6 Assigning property values, Cascading, and Inheritancew3.org
  39. A quick introduction to CSS @scopebram.us
  40. CSS Cascading and Inheritance Level 4w3.org
  41. Control CSS cascade with cascade layers - LogRocket Blogblog.logrocket.com
  42. CSS Cascade Layers (@layer): The Complete Guide to Taming Specificity (2026)cssawwwards.com
  43. Limit the reach of your selectors with the CSS @scope at-ruledeveloper.chrome.com
  44. @scope CSS at-rule - CSSdeveloper.mozilla.org
  45. Introduction to the CSS cascade - MDN Web Docsdeveloper.mozilla.org
  46. CSS Cascade Layers Guide - @layer Ruledesign.dev
  47. @scope — Scoped Styles - Dev Guidescamoa.github.io
  48. CSS property value processing - MDN Web Docsdeveloper.mozilla.org
  49. 6 Assigning property values, Cascading, and Inheritancew3.org
  50. Value - MDN Web Docs Glossary: Definitions of Web-related termsdeveloper.mozilla.org
  51. Actual value - CSS: Cascading Style Sheetsudn.realityripple.com
  52. Using CSS custom properties (variables)developer.mozilla.org
  53. CSS Variables: A Complete Guide [2026]scrimba.com
  54. CSS Length Units: px, em, rem, vw, vh, and Moreitechguides.com
  55. clamp() CSS function - MDN Web Docsdeveloper.mozilla.org
  56. CSS Units Explained: px vs rem vs em vs vw - Blogtoolbox-kit.com
  57. CSS Units — px, em, rem, vw, vh Explainedtutorialslogic.com
  58. box sizingdeveloper.mozilla.org
  59. box-sizingcss-tricks.com
  60. CSS Grid Layout Module Level 2w3.org
  61. Box Modelweb.dev
  62. Introduction to the CSS box model - MDN Web Docsdeveloper.mozilla.org
  63. CSS Box Model: How to Use CSS Box Sizingthevalleyofcode.com
  64. Subgrid moved to Level 2 of the CSS Grid specificationrachelandrew.co.uk
  65. Subgridtympanus.net
  66. CSS Media Queries: The Complete Guide for 2026devtoolbox.dedyn.io
  67. Responsive web designen.wikipedia.org
  68. prefers-color-scheme - Modern CSS Dailymodern-css.davecross.co.uk
  69. The complete guide to CSS media queriespolypane.app
  70. Using container size and style queries - CSS - MDN Web Docsdeveloper.mozilla.org
  71. Complete Guide to CSS Container Queriesmoderncsstools.com
  72. Responsive Web Design History: Ethan Marcotte's 2010 A List Apart Revolutionsomanyquestions.show
  73. An Introduction to Responsive Web Designixdf.org
  74. Media Queries Level 5w3.org
  75. Dark Mode in CSScss-tricks.com
  76. CSS Prefers-Color-Scheme: Complete Guide to Dark Mode and Light Mode Detection - CodeLuckycodelucky.com
  77. container-type CSS property - MDN Web Docsdeveloper.mozilla.org
  78. Container queries begin to land in stable browsers while the polyfill gets a big updatedeveloper.chrome.com
  79. Getting started with CSS container queries - MDN Web Docsdeveloper.mozilla.org
  80. Container queriesweb.dev
  81. Responsive web design (RWD)ebsco.com
  82. Oklab color spaceen.wikipedia.org
  83. Modern CSS Color: oklch, color-mix(), and the New Color Spacesmoderncsstools.com
  84. color-mix() CSS function - MDN Web Docs - Mozilladeveloper.mozilla.org
  85. CSS color-mix(): Native Color Blending That Retires Your Sass Pipeline — W3Tweaksw3tweaks.com
  86. Optimize WebFont loading and renderingweb.dev
  87. CSS @font-face — Web Font Loading Strategies - Wu Wenjuntie.pub
  88. A New Way To Reduce Font Loading Impact: CSS Font Descriptors — Smashing Magazinesmashingmagazine.com
  89. CSS color-mix()developer.chrome.com
  90. CSS Blend Modes for Images — Mix-Blend-Mode, Backdrop-Filter, and Isolation Without JavaScriptppimage.com
  91. mix-blend-mode CSS property - MDN Web Docsdeveloper.mozilla.org
  92. Using CSS backdrop-filter for UI Effectscss-tricks.com
  93. Filter Effects Module Level 2drafts.csswg.org
  94. CSS color-mix() Playground - Mix Colors Across Color Spacesmoderncsstools.com
  95. color-mix(): blending colors in CSS — cssShowcasecssshowcase.com
  96. Backdrop Root Proposal [archived copy]lists.w3.org
  97. Transitionsweb.dev
  98. transition-timing-function CSS property - MDN Web Docsdeveloper.mozilla.org
  99. transition-timing-functioncss-tricks.com
  100. CSS Transitions Module Level 1w3.org
  101. CSS Scroll-Driven Animationsmskelton.dev
  102. A guide to Scroll-driven Animations with just CSSwebkit.org
  103. CSS Scroll-Driven Animations: Scroll Timelines Guide (2026)cssawwwards.com
  104. An Introduction To CSS Scroll-Driven Animations: Scroll And View Progress Timelines — Smashing Magazinesmashingmagazine.com
  105. The View Transitions API And Delightful UI Animations (Part 1) — Smashing Magazinesmashingmagazine.com
  106. Scroll-driven Animations - CSS Working Group Editor Draftsdrafts.csswg.org
  107. CSS Scroll-Driven Animations: Complete Guide (No JavaScript)csstools.io
  108. view-transitions/explainer.md at main · WICG/view-transitionsgithub.com
  109. CSS View Transitions: From Basic to Advancedmoderncsstools.com
  110. An Introduction to the View Transitions API — SitePointsitepoint.com
  111. CSS Paged Media Module & Specificationsdocraptor.com
  112. 13. Paged mediaw3.org
  113. CSS Paged Media: The Complete Guide to Print & PDF Styling - Doppiodoppio.sh
  114. Media Queries Level 3w3.org
  115. Media typesw3.org
  116. CSS media query with `@media speech` - Screen reader compatibilitypowermapper.com
  117. All CSS specificationsw3.org
  118. Emulate CSS media featuresdeveloper.chrome.com
  119. prefers-reduced-motion CSS media feature - MDN Web Docsdeveloper.mozilla.org
  120. Preference Queries12daysofweb.dev
  121. CSS media features to improve accessibility — Blog on Digital Accessibilitya11y-blog.dev
  122. Respecting Reduced Motion and Forced Colorsmv3-extension.com
  123. Media Query Preferences: Respect User Choices in Web Interfacesbotbrowser.io
  124. CSS Media Typesquackit.com
  125. Aural CSS: Support for CSS 2 Aural Style Sheets / CSS 3 Speech Module from Dotjay’s Lab - dotjay.comlab.dotjay.com
  126. CSS Preprocessors: Sass vs Less. CSS Preprocessors are scripting…medium.com
  127. Popular CSS preprocessors with examples: Sass, Less, Stylus and more · Raygun Blograygun.com
  128. CSS Preprocessors: SASS and LESS - NamasteDev Blogsnamastedev.com
  129. An Introduction to PostCSS — SitePointsitepoint.com
  130. autoprefixer coregithub.com
  131. minifier-css-postcss - Packospherepackosphere.com
  132. BEM CSS naming conventions including ABEM & BBEMpivale.co
  133. BEM CSS Methodology: A Step-by-Step Guide for Beginnersvaloremreply.com
  134. BEM by Example: Best Practices for BEM CSS Namingsparkbox.com
  135. Setting Up Your Development Environment with PostCSS and Autoprefixer — ResumeLens Tailwind CSS Blogresumelens.org
  136. Understanding BEM as a CSS Methodology for Modern Web Development - DEV Communitydev.to
  137. Inside the Browser Rendering Pipeline - Aleksandar Gjoreskialeksandargjoreski.dev
  138. Critical rendering path - Performance - MDN Web Docsdeveloper.mozilla.org
  139. Is Vendor Prefixing Dead?css-tricks.com
  140. Baselineweb.dev
  141. How the Browser Rendering Pipeline Actually Works - DEV Communitydev.to
  142. CSS Vendor Prefixesbitsofco.de
  143. Vendor prefix - Glossary - MDN Web Docsdeveloper.mozilla.org
  144. Vendor prefixdeveloper.mozilla.org
  145. Baseline (compatibility)developer.mozilla.org
  146. Simplify Browser Compatibility Decisions with Baselinedockyard.com
  147. CSS Object Model (CSSOM)w3.org
  148. CSS Object Model (CSSOM)developer.mozilla.org
  149. Using dynamic styling information - Web APIsdeveloper.mozilla.org
  150. Using dynamic styling information - Web APIsdevdoc.net
  151. Window: getComputedStyle() method - Web APIsdeveloper.mozilla.org
  152. Window.getComputedStyle() - Web APIsmdn2.netlify.app
  153. CSSStyleProperties - Web APIsdeveloper.mozilla.org
  154. Houdini APIsdeveloper.mozilla.org
  155. CSS Houdini: Properties, Values, and the Paint API - Moment For Technologymo4tech.com
  156. Say Hello to Houdini and the CSS Paint API / Coder's Blockcodersblock.com
  157. The Ultimate Guide to CSS Houdinitomquinonero.com
  158. CSS Object Model (CSSOM) - Web APIsdeveloper.mozilla.org
  159. Fix: Eliminate Render-Blocking CSS and JavaScriptsitegrade.io
  160. How to Eliminate Render-Blocking Resources (CSS and JavaScript)nitropack.io
  161. CSS Scope Proposal & Explainer - OddBird CSS Sandboxcss.oddbird.net
  162. The End of Global CSS. CSS selectors all exist within the same…medium.com
  163. Building a Scalable CSS Architecture With BEM and Utility Classescss-tricks.com
  164. CSS @Layer: Complete Guide to Cascade Layersdigitalthriveai.com
  165. CSS Nesting and Cascade: Elevating Web Design - DZonedzone.com
  166. Cascade Layers (@layer) in CSS: how to solve the specificity problem once and for all - DEV Communitydev.to
  167. Render-blocking CSSweb.dev
  168. How to eliminate render-blocking resources — CSS and JavaScript - LogRocket Blogblog.logrocket.com
  169. Tackling Render Blocking CSS for a Fast Rendering Website — SitePointsitepoint.com
  170. How to Eliminate Render-blocking Resources - SiteGround Academysiteground.com
  171. Critical CSS? Not So Fast!csswizardry.com
  172. How To Fix & Eliminate Render Blocking Resources For Page Speedpagespeedchecklist.com
  173. Fix Render-Blocking CSS: 2026 Guidewebperfclinic.com
  174. How CSS modules solve global scope in CSSmstamstrom.medium.com
  175. CSS Cascade Layers Explainercss.oddbird.net
  176. Cascade Layers Guidecss-tricks.com
  177. CSS @scope: the end of BEM (for real this time) - Web Makerwebmaker.app
  178. CSS @layer: Cascade Layers That End the Specificity Wars — W3Tweaksw3tweaks.com
  179. CSS Mixins & Functions Explainercss.oddbird.net
  180. CSS Functions and Mixins Module Notescss-tricks.com
  181. CSS Functions and Mixins Module Notestechreport.ngo
  182. Intent to Ship: CSS Custom Functions (@function)groups.google.com
  183. Compatibility with the CSS custom function and mixin proposal · Issue #3787 · sass/sassgithub.com
  184. CSS Anchor Positioning and Popover API Hit Baseline 2026: The End of JavaScript Tooltip Librariesfull-net.cz
  185. CSS Anchor Positioning: The Complete Guide (2026)ultimatedesigntools.com
  186. CSS Anchor Positioning: Tooltips Without JS — CODERCOPSblog.codercops.com
  187. CSS Anchor Positioning Reaches Baseline in 2026refontelearning.com
  188. CSS Anchor Positioning: No More JavaScript for Your Tooltips and Popovers - Kevin Kenfackkenfack.vercel.app
  189. CSS Anchor Positioning: Browser Support, Features, Issuestestmuai.com
  190. CSS Cascading and Inheritance Level 6w3.org
  191. CSS Cascade 6 (Scope)miriamsuzanne.com
  192. [css-scoping] Proposal for light-dom scoping/namespacing with re-designed `@scope` rule · Issue #5809 · w3c/csswg-draftsgithub.com
  193. The Future of CSS: Cascade Layers (CSS @layer)bram.us
  194. PROPOSED CSS Working Group Charterw3c.github.io
  195. add @mixin and @function · Issue #7301 · Fyrd/caniusegithub.com
  196. `@mixin` · tailwindlabs/tailwindcss · Discussion #14100github.com
  197. support for CSS Mixins & Functions · Issue #785 · web-platform-tests/interopgithub.com