{
  "id": "cascading-style-sheets",
  "title": "Cascading Style Sheets",
  "lang": "en",
  "source_lang": "en",
  "summary": "CSS is a style sheet language that controls how markup-based documents, mainly web pages, are presented, separating appearance from structure.",
  "category": "computer-science",
  "subcategory": "software",
  "type": "concept",
  "aliases": [
    "CSS"
  ],
  "generated_at": "2026-10-08",
  "model": "pro/claude-haiku-5-5",
  "url": "https://aiwiki.page/en/cascading-style-sheets/",
  "translations": {
    "zh-Hans": {
      "url": "https://aiwiki.page/zh/cascading-style-sheets/",
      "json": "https://aiwiki.page/zh/cascading-style-sheets.json"
    }
  },
  "sections": [
    {
      "heading": "",
      "text": "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.\n\nThe 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.\n\nThis 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."
    },
    {
      "heading": "Definition and scope",
      "text": "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.\n\nThe 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.\n\nCSS 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.\n\nh1 {\n  color: navy;\n  font-size: 2rem;\n}\n\nCSS 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.\n\nWithin 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."
    },
    {
      "heading": "Origins and early development",
      "text": "Proposal at CERN\n\nCSS 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 .\n\nThe 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.\n\nInformal drafts and early collaborators\n\nLie'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.\n\nAdoption by the W3C (1994–1995)\n\nThe 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.\n\nCSS level 1 and level 2\n\nThe 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.\n\nCSS2 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 ."
    },
    {
      "heading": "Standardization and the module model",
      "text": "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.\n\nFrom Candidate Recommendation to Recommendation\n\nThe 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.\n\nFrom monolithic levels to independent modules\n\nCSS 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).\n\nLater 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.\n\nAnnual snapshots\n\nThe 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.\n\nWorking group and gating\n\nThe 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."
    },
    {
      "heading": "Syntax and parsing",
      "text": "Rules, selectors and declarations\n\nA 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.\n\nAt-rules\n\nAt-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.\n\nTokenization and error recovery\n\nParsing 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.\n\nEmbedding styles and processing order\n\nCSS 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."
    },
    {
      "heading": "Selectors and specificity",
      "text": "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.\n\nCombinators and structural matching\n\nCombinators 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.\n\nSeveral 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.\n\nHow specificity ranks selectors\n\nWhen 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)\\), where \\(a\\) counts inline style attributes, \\(b\\) counts ID selectors, \\(c\\) counts class, attribute and pseudo-class selectors, and \\(d\\) 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)\\) therefore beats \\((0,0,99,99)\\). For example, the selector #nav li.active a:hover has the weight \\((0,1,2,2)\\): one ID, two classes or pseudo-classes (.active and :hover), and two type selectors (li and a).\n\nTwo 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.\n\nSource order as the tie-breaker\n\nIf 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."
    },
    {
      "heading": "The cascade, inheritance, and cascade layers",
      "text": "Origins and importance\n\nEach 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.\n\nOrigin 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.\n\nThe !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.\n\nInheritance and defaulting keywords\n\nNot 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.\n\nFour 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.\n\nCascade layers\n\nCascade 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.\n\nThe 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.\n\nScoping with @scope\n\nThe @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.\n\n@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."
    },
    {
      "heading": "Value computation and units",
      "text": "From declared value to actual value\n\nA 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.\n\nThe 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.\n\nLength units\n\nLength 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.\n\nRelative 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.\n\nMath functions and fluid sizing\n\nThe 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 \\(\\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.\n\nThese 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.\n\nCustom properties and var()\n\nCustom 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.\n\nUnlike 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."
    },
    {
      "heading": "Box model and layout systems",
      "text": "The box model\n\nEvery 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.\n\nBy 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 \\(W_{\\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.\n\nSetting 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.\n\nDisplay, flow, and formatting contexts\n\nThe 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.\n\nPositioning and stacking\n\nThe 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.\n\nPositioned 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.\n\nFlexbox and Grid\n\nFlexbox 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.\n\nGrid 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.\n\nGrid 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."
    },
    {
      "heading": "Responsive design and media queries",
      "text": "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.\n\nMedia queries\n\nThe @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.\n\nThe 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.\n\nContainer queries\n\nContainer 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.\n\nAn 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.\n\nContainer 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.\n\nFluid layouts and relative units\n\nMedia 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.\n\nEthan 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.\n\nReduced reliance on scripting\n\nBefore 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."
    },
    {
      "heading": "Color, typography, and visual styling",
      "text": "Color models and color-mix()\n\nEarly 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.\n\nThe 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().\n\nFonts, font loading, and text\n\nCustom 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.\n\nThe <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.\n\nFont 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.\n\nBackgrounds, borders, shadows, gradients, and images\n\nA 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>.\n\nFilters, blend modes, and transforms\n\nCSS 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.\n\nThe <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.\n\nThe 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."
    },
    {
      "heading": "Transitions, animation, and interactivity",
      "text": "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.\n\nTransitions\n\nA 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.\n\nTiming 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.\n\nTransitions 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.\n\nKeyframe animations\n\nTransitions 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.\n\nScroll-driven animations\n\nOrdinary 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.\n\nWith 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.\n\nThe View Transitions API\n\nAnimating 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.\n\nThe 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.\n\nBecause 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."
    },
    {
      "heading": "Print, accessibility, and user preferences",
      "text": "Paged media and printing\n\nCSS 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.\n\nPage 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.\n\nMedia types\n\nMedia 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.\n\nThe 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.\n\nPreference queries\n\nPreference 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.\n\nThe 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.\n\nAccessibility concerns\n\nAccessibility 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.\n\nCSS 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."
    },
    {
      "heading": "Tooling, preprocessors, and methodologies",
      "text": "Preprocessors\n\nPreprocessors 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.\n\nSass 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.\n\nPost-processors and build pipelines\n\nA 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.\n\nOrder 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.\n\nNaming methodologies\n\nBecause 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.\n\nUtility-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.\n\nTrade-offs\n\nNo 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."
    },
    {
      "heading": "Browser implementation and rendering",
      "text": "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.\n\nThe 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.\n\nBecause 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.\n\nVendor 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.\n\nFeature 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.\n\nOn 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."
    },
    {
      "heading": "Relations with HTML, the DOM, and JavaScript",
      "text": "Linking styles to markup\n\nCSS 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.\n\nThe CSS Object Model and scripts\n\nThe 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..\n\nTwo 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..\n\nThe 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..\n\nPerformance 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.\n\nCustom properties as a bridge\n\nCustom 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..\n\nHoudini-style APIs\n\nCSS 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..\n\nThe 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..\n\nThese 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."
    },
    {
      "heading": "Performance, maintenance, and criticism",
      "text": "Render blocking and loading cost\n\nBrowsers 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.\n\nOptimization 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.\n\nCritics 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.\n\nGlobal scope and the specificity problem\n\nAlmost 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.\n\nThe 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.\n\nDebates over nesting and layers\n\nThe 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.\n\nNative 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.\n\nThe 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.\n\nStandardization and uneven adoption\n\nStandardization 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."
    },
    {
      "heading": "Future directions and open problems",
      "text": "Native functions and mixins\n\nThe 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.\n\nThe 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.\n\nNative 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.\n\nAnchor positioning and other layout work\n\nAnchor 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.\n\nBrowser 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.\n\nBeyond 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.\n\nCascade, scoping and color\n\nScoping 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.\n\nCascade 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.\n\nOn colour, Color Level 4 extends the range of color spaces beyond sRGB, and further colour-space and gradient work continues in later drafts.\n\nStandards process and compatibility\n\nAnnual 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.\n\nThe 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."
    }
  ],
  "links": [
    "html",
    "world-wide-web",
    "javascript",
    "cern",
    "printing",
    "disability",
    "unicode"
  ],
  "sources": [
    {
      "title": "Håkon Wium Lie, the Creator of CSS, at Codemotion Milan",
      "url": "https://www.codemotion.com/magazine/dev-life/css-creator-hakon-wium-lie-at-codemotion-milan/"
    },
    {
      "title": "A brief history of CSS until 2016",
      "url": "https://www.w3.org/Style/CSS20/history.html"
    },
    {
      "title": "History of CSS",
      "url": "https://www.sitesbay.com/css/css-history"
    },
    {
      "title": "A Brief History of CSS",
      "url": "https://www.shecodes.io/challenge_submissions/197698/embed"
    },
    {
      "title": "W3C PR-CSS1-961112",
      "url": "https://www.w3.org/TR/PR-CSS1-961112"
    },
    {
      "title": "201: Levels of CSS",
      "url": "https://russmaxdesign.github.io/maxdesign-slides/02-css/201-levels-of-css.html"
    },
    {
      "title": "W3C Issues CSS2 as a Proposed Recommendation",
      "url": "https://www.w3.org/press-releases/1998/css2-pr/"
    },
    {
      "title": "The World Wide Web Consortium Issues CSS2 as a W3C Recommendation",
      "url": "https://www.w3.org/press-releases/1998/css2"
    },
    {
      "title": "REC-CSS2-19980512 Cascading Style Sheets, level 2 CSS2 Specification",
      "url": "https://www.w3.org/TR/1998/REC-CSS2-19980512/css2.pdf"
    },
    {
      "title": "REC CSS1 20080411",
      "url": "https://www.w3.org/TR/2008/REC-CSS1-20080411"
    },
    {
      "title": "Cascading Style Sheet (CSS) File Format",
      "url": "https://www.loc.gov/preservation/digital/formats/fdd/fdd000482.shtml"
    },
    {
      "title": "CSS current work & how to participate",
      "url": "https://www.w3.org/Style/CSS/current-work.en.html"
    },
    {
      "title": "W3C Process Document",
      "url": "https://www.w3.org/Consortium/Process/Process-19991111/tr.html"
    },
    {
      "title": "CSS Snapshot 2025",
      "url": "https://www.w3.org/TR/css-2025/"
    },
    {
      "title": "CSS Working Group Charter",
      "url": "https://w3c.github.io/charter-drafts/2022/css-2022.html"
    },
    {
      "title": "WD css beijing 20071019",
      "url": "https://www.w3.org/TR/2007/WD-css-beijing-20071019"
    },
    {
      "title": "CSS Snapshot 2018",
      "url": "https://www.w3.org/TR/css-2018/"
    },
    {
      "title": "CSS Snapshot 2023",
      "url": "https://www.w3.org/TR/css-2023/"
    },
    {
      "title": "CSS Snapshot 2020",
      "url": "https://www.w3.org/TR/css-2020/"
    },
    {
      "title": "CSS Snapshot 2026",
      "url": "https://www.w3.org/TR/css-2026/"
    },
    {
      "title": "Publications",
      "url": "https://www.w3.org/groups/wg/css/publications/"
    },
    {
      "title": "CSS Syntax Module Level 3",
      "url": "https://www.w3.org/TR/css-syntax-3/"
    },
    {
      "title": "At-rules - CSS - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Syntax/At-rules"
    },
    {
      "title": "CSS error handling - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Syntax/Error_handling"
    },
    {
      "title": "CSS Syntax Module Level 3",
      "url": "https://www.w3.org/TR/css-syntax-3/Overview.html"
    },
    {
      "title": "CSS @import Rule",
      "url": "https://www.w3docs.com/learn-css/import"
    },
    {
      "title": "Introduction to CSS syntax: declarations, rulesets, and statements - CSS",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Syntax/Introduction"
    },
    {
      "title": "The Quick Guide to CSS Specificity - Slicejack",
      "url": "https://slicejack.com/quick-guide-to-css-specificity/"
    },
    {
      "title": "Specificity - CSS - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Cascade/Specificity"
    },
    {
      "title": ":is() vs. :where()",
      "url": "https://gomakethings.com/is-vs.-where/"
    },
    {
      "title": "where() CSS pseudo-class - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:where"
    },
    {
      "title": "Selector list - CSS - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/Selector_list"
    },
    {
      "title": ":where",
      "url": "https://css-tricks.com/almanac/pseudo-selectors/w/where/"
    },
    {
      "title": "Specifics on CSS Specificity",
      "url": "https://css-tricks.com/specifics-on-css-specificity/"
    },
    {
      "title": "Screencast: Origin and Importance in the CSS Cascade — SitePoint",
      "url": "https://www.sitepoint.com/screencast-origin-importance-css-cascade/"
    },
    {
      "title": "The cascade - CSS",
      "url": "https://web.dev/learn/css/the-cascade"
    },
    {
      "title": "Cascade layers - Learn web development",
      "url": "https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Cascade_layers"
    },
    {
      "title": "6 Assigning property values, Cascading, and Inheritance",
      "url": "https://www.w3.org/TR/1998/REC-CSS2-19980512/cascade.html"
    },
    {
      "title": "A quick introduction to CSS @scope",
      "url": "https://www.bram.us/2023/08/22/a-quick-introduction-to-css-scope/"
    },
    {
      "title": "CSS Cascading and Inheritance Level 4",
      "url": "https://www.w3.org/TR/css-cascade-4/"
    },
    {
      "title": "Control CSS cascade with cascade layers - LogRocket Blog",
      "url": "https://blog.logrocket.com/control-css-cascade-with-cascade-layers/"
    },
    {
      "title": "CSS Cascade Layers (@layer): The Complete Guide to Taming Specificity (2026)",
      "url": "https://cssawwwards.com/blog/css-cascade-layers-guide-2026"
    },
    {
      "title": "Limit the reach of your selectors with the CSS @scope at-rule",
      "url": "https://developer.chrome.com/docs/css-ui/at-scope"
    },
    {
      "title": "@scope CSS at-rule - CSS",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@scope"
    },
    {
      "title": "Introduction to the CSS cascade - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Cascade/Introduction"
    },
    {
      "title": "CSS Cascade Layers Guide - @layer Rule",
      "url": "https://design.dev/guides/css-cascade-layers/"
    },
    {
      "title": "@scope — Scoped Styles - Dev Guides",
      "url": "https://camoa.github.io/dev-guides/css/modern-css/css-scope/"
    },
    {
      "title": "CSS property value processing - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Cascade/Property_value_processing"
    },
    {
      "title": "6 Assigning property values, Cascading, and Inheritance",
      "url": "https://www.w3.org/TR/CSS2/cascade.html"
    },
    {
      "title": "Value - MDN Web Docs Glossary: Definitions of Web-related terms",
      "url": "https://developer.mozilla.org/en-US/docs/Glossary/value"
    },
    {
      "title": "Actual value - CSS: Cascading Style Sheets",
      "url": "https://udn.realityripple.com/docs/Web/CSS/actual_value"
    },
    {
      "title": "Using CSS custom properties (variables)",
      "url": "https://developer.mozilla.org/en/docs/Web/CSS/Using_CSS_custom_properties"
    },
    {
      "title": "CSS Variables: A Complete Guide [2026]",
      "url": "https://scrimba.com/articles/css-variables-complete-guide-2026/"
    },
    {
      "title": "CSS Length Units: px, em, rem, vw, vh, and More",
      "url": "https://www.itechguides.com/css-length-units-a-practical-guide-to-px-em-rem-vw-vh-and-more/"
    },
    {
      "title": "clamp() CSS function - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/clamp"
    },
    {
      "title": "CSS Units Explained: px vs rem vs em vs vw - Blog",
      "url": "https://www.toolbox-kit.com/blog/css-units-explained-px-rem-em-vw"
    },
    {
      "title": "CSS Units — px, em, rem, vw, vh Explained",
      "url": "https://www.tutorialslogic.com/css/units"
    },
    {
      "title": "box sizing",
      "url": "https://developer.mozilla.org/en-us/docs/web/css/box-sizing"
    },
    {
      "title": "box-sizing",
      "url": "https://css-tricks.com/almanac/properties/b/box-sizing/"
    },
    {
      "title": "CSS Grid Layout Module Level 2",
      "url": "https://www.w3.org/TR/css-grid-2/"
    },
    {
      "title": "Box Model",
      "url": "https://web.dev/learn/css/box-model"
    },
    {
      "title": "Introduction to the CSS box model - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Box_model/Introduction"
    },
    {
      "title": "CSS Box Model: How to Use CSS Box Sizing",
      "url": "https://thevalleyofcode.com/lesson/css-box-model/box-sizing/"
    },
    {
      "title": "Subgrid moved to Level 2 of the CSS Grid specification",
      "url": "https://rachelandrew.co.uk/archives/2017/03/16/subgrid-moved-to-level-2-of-the-css-grid-specification/"
    },
    {
      "title": "Subgrid",
      "url": "https://tympanus.net/codrops/css_reference/subgrid/"
    },
    {
      "title": "CSS Media Queries: The Complete Guide for 2026",
      "url": "https://devtoolbox.dedyn.io/blog/css-media-queries-complete-guide"
    },
    {
      "title": "Responsive web design",
      "url": "https://en.wikipedia.org/wiki/Responsive_web_design"
    },
    {
      "title": "prefers-color-scheme - Modern CSS Daily",
      "url": "https://modern-css.davecross.co.uk/2026/09/21/prefers-color-scheme/"
    },
    {
      "title": "The complete guide to CSS media queries",
      "url": "https://polypane.app/blog/the-complete-guide-to-css-media-queries/"
    },
    {
      "title": "Using container size and style queries - CSS - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Containment/Container_size_and_style_queries"
    },
    {
      "title": "Complete Guide to CSS Container Queries",
      "url": "https://moderncsstools.com/guides/container-queries/"
    },
    {
      "title": "Responsive Web Design History: Ethan Marcotte's 2010 A List Apart Revolution",
      "url": "https://somanyquestions.show/tech/responsive-web-design-history/"
    },
    {
      "title": "An Introduction to Responsive Web Design",
      "url": "https://ixdf.org/literature/article/an-introduction-to-responsive-web-design"
    },
    {
      "title": "Media Queries Level 5",
      "url": "https://www.w3.org/TR/mediaqueries-5/"
    },
    {
      "title": "Dark Mode in CSS",
      "url": "https://css-tricks.com/dark-modes-with-css/"
    },
    {
      "title": "CSS Prefers-Color-Scheme: Complete Guide to Dark Mode and Light Mode Detection - CodeLucky",
      "url": "https://codelucky.com/css-prefers-color-scheme/"
    },
    {
      "title": "container-type CSS property - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/container-type"
    },
    {
      "title": "Container queries begin to land in stable browsers while the polyfill gets a big update",
      "url": "https://developer.chrome.com/blog/cq-polyfill"
    },
    {
      "title": "Getting started with CSS container queries - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/blog/getting-started-with-css-container-queries/"
    },
    {
      "title": "Container queries",
      "url": "https://web.dev/learn/css/container-queries"
    },
    {
      "title": "Responsive web design (RWD)",
      "url": "https://www.ebsco.com/research-starters/computer-science/responsive-web-design-rwd/"
    },
    {
      "title": "Oklab color space",
      "url": "https://en.wikipedia.org/wiki/Oklab_color_space"
    },
    {
      "title": "Modern CSS Color: oklch, color-mix(), and the New Color Spaces",
      "url": "https://moderncsstools.com/guides/modern-colors/"
    },
    {
      "title": "color-mix() CSS function - MDN Web Docs - Mozilla",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/color-mix"
    },
    {
      "title": "CSS color-mix(): Native Color Blending That Retires Your Sass Pipeline — W3Tweaks",
      "url": "https://www.w3tweaks.com/css/css-color-mix-explained/"
    },
    {
      "title": "Optimize WebFont loading and rendering",
      "url": "https://web.dev/articles/optimize-webfont-loading"
    },
    {
      "title": "CSS @font-face — Web Font Loading Strategies - Wu Wenjun",
      "url": "https://tie.pub/en/blog/web-font-loading-strategies/"
    },
    {
      "title": "A New Way To Reduce Font Loading Impact: CSS Font Descriptors — Smashing Magazine",
      "url": "https://www.smashingmagazine.com/2021/05/reduce-font-loading-impact-css-descriptors/"
    },
    {
      "title": "CSS color-mix()",
      "url": "https://developer.chrome.com/docs/css-ui/css-color-mix"
    },
    {
      "title": "CSS Blend Modes for Images — Mix-Blend-Mode, Backdrop-Filter, and Isolation Without JavaScript",
      "url": "https://www.ppimage.com/blog/css-image-blend-modes-guide"
    },
    {
      "title": "mix-blend-mode CSS property - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/mix-blend-mode"
    },
    {
      "title": "Using CSS backdrop-filter for UI Effects",
      "url": "https://css-tricks.com/using-css-backdrop-filter-for-ui-effects/"
    },
    {
      "title": "Filter Effects Module Level 2",
      "url": "https://drafts.csswg.org/filter-effects-2/"
    },
    {
      "title": "CSS color-mix() Playground - Mix Colors Across Color Spaces",
      "url": "https://moderncsstools.com/color-mix-playground/"
    },
    {
      "title": "color-mix(): blending colors in CSS — cssShowcase",
      "url": "https://www.cssshowcase.com/articles/color/color-mix"
    },
    {
      "title": "Backdrop Root Proposal [archived copy]",
      "url": "https://lists.w3.org/Archives/Public/www-archive/2019Mar/0000.html"
    },
    {
      "title": "Transitions",
      "url": "https://web.dev/learn/css/transitions"
    },
    {
      "title": "transition-timing-function CSS property - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/transition-timing-function"
    },
    {
      "title": "transition-timing-function",
      "url": "https://css-tricks.com/almanac/properties/t/transition-timing-function/"
    },
    {
      "title": "CSS Transitions Module Level 1",
      "url": "https://www.w3.org/TR/css-transitions-1/"
    },
    {
      "title": "CSS Scroll-Driven Animations",
      "url": "https://mskelton.dev/blog/css-scroll-animations"
    },
    {
      "title": "A guide to Scroll-driven Animations with just CSS",
      "url": "https://webkit.org/blog/17101/a-guide-to-scroll-driven-animations-with-just-css/"
    },
    {
      "title": "CSS Scroll-Driven Animations: Scroll Timelines Guide (2026)",
      "url": "https://cssawwwards.com/blog/css-scroll-driven-animations-guide-2026"
    },
    {
      "title": "An Introduction To CSS Scroll-Driven Animations: Scroll And View Progress Timelines — Smashing Magazine",
      "url": "https://www.smashingmagazine.com/2024/12/introduction-css-scroll-driven-animations/"
    },
    {
      "title": "The View Transitions API And Delightful UI Animations (Part 1) — Smashing Magazine",
      "url": "https://www.smashingmagazine.com/2023/12/view-transitions-api-ui-animations-part1/"
    },
    {
      "title": "Scroll-driven Animations - CSS Working Group Editor Drafts",
      "url": "https://drafts.csswg.org/scroll-animations/"
    },
    {
      "title": "CSS Scroll-Driven Animations: Complete Guide (No JavaScript)",
      "url": "https://csstools.io/blog/css-scroll-driven-animations"
    },
    {
      "title": "view-transitions/explainer.md at main · WICG/view-transitions",
      "url": "https://github.com/WICG/view-transitions/blob/main/explainer.md"
    },
    {
      "title": "CSS View Transitions: From Basic to Advanced",
      "url": "https://moderncsstools.com/guides/view-transitions/"
    },
    {
      "title": "An Introduction to the View Transitions API — SitePoint",
      "url": "https://www.sitepoint.com/view-transitions-api-introduction/"
    },
    {
      "title": "CSS Paged Media Module & Specifications",
      "url": "https://docraptor.com/css-paged-media"
    },
    {
      "title": "13. Paged media",
      "url": "https://www.w3.org/TR/CSS2/page.html"
    },
    {
      "title": "CSS Paged Media: The Complete Guide to Print & PDF Styling - Doppio",
      "url": "https://doppio.sh/guide/css-paged-media"
    },
    {
      "title": "Media Queries Level 3",
      "url": "https://www.w3.org/TR/mediaqueries-3/"
    },
    {
      "title": "Media types",
      "url": "https://www.w3.org/TR/2011/REC-CSS2-20110607/media.html"
    },
    {
      "title": "CSS media query with `@media speech` - Screen reader compatibility",
      "url": "https://www.powermapper.com/tests/screen-readers/content/media-query-speech/"
    },
    {
      "title": "All CSS specifications",
      "url": "https://www.w3.org/Style/CSS/specs.en.html"
    },
    {
      "title": "Emulate CSS media features",
      "url": "https://developer.chrome.com/docs/devtools/rendering/emulate-css"
    },
    {
      "title": "prefers-reduced-motion CSS media feature - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/prefers-reduced-motion"
    },
    {
      "title": "Preference Queries",
      "url": "https://12daysofweb.dev/2021/preference-queries"
    },
    {
      "title": "CSS media features to improve accessibility — Blog on Digital Accessibility",
      "url": "https://a11y-blog.dev/en/articles/css-media-features-for-a11y/"
    },
    {
      "title": "Respecting Reduced Motion and Forced Colors",
      "url": "https://mv3-extension.com/uiux-patterns-interactive-components/internationalization-accessibility/respecting-reduced-motion-and-forced-colors/"
    },
    {
      "title": "Media Query Preferences: Respect User Choices in Web Interfaces",
      "url": "https://botbrowser.io/en/blog/media-query-preferences-and-user-control/"
    },
    {
      "title": "CSS Media Types",
      "url": "https://www.quackit.com/css/css_media_types.cfm"
    },
    {
      "title": "Aural CSS: Support for CSS 2 Aural Style Sheets / CSS 3 Speech Module from Dotjay’s Lab - dotjay.com",
      "url": "https://lab.dotjay.com/notes/css/aural-speech/"
    },
    {
      "title": "CSS Preprocessors: Sass vs Less. CSS Preprocessors are scripting…",
      "url": "https://medium.com/@lelianto.eko/css-preprocessors-sass-vs-less-393cd6621467"
    },
    {
      "title": "Popular CSS preprocessors with examples: Sass, Less, Stylus and more · Raygun Blog",
      "url": "https://raygun.com/blog/css-preprocessors-examples/"
    },
    {
      "title": "CSS Preprocessors: SASS and LESS - NamasteDev Blogs",
      "url": "https://namastedev.com/blog/css-preprocessors-sass-and-less/"
    },
    {
      "title": "An Introduction to PostCSS — SitePoint",
      "url": "https://www.sitepoint.com/an-introduction-to-postcss/"
    },
    {
      "title": "autoprefixer core",
      "url": "https://github.com/radium-v/autoprefixer-core"
    },
    {
      "title": "minifier-css-postcss - Packosphere",
      "url": "https://packosphere.com/meteor/minifier-css-postcss"
    },
    {
      "title": "BEM CSS naming conventions including ABEM & BBEM",
      "url": "https://www.pivale.co/resources/blog/bem-css-abem-bbem"
    },
    {
      "title": "BEM CSS Methodology: A Step-by-Step Guide for Beginners",
      "url": "https://www.valoremreply.com/resources/insights/guide/bem-methodology-a-step-by-step-guide-for-beginners/"
    },
    {
      "title": "BEM by Example: Best Practices for BEM CSS Naming",
      "url": "https://sparkbox.com/foundry/bem_by_example"
    },
    {
      "title": "Setting Up Your Development Environment with PostCSS and Autoprefixer — ResumeLens Tailwind CSS Blog",
      "url": "https://www.resumelens.org/blog/tailwind/setting-up-your-development-environment-with-postcss-and-autoprefixer"
    },
    {
      "title": "Understanding BEM as a CSS Methodology for Modern Web Development - DEV Community",
      "url": "https://dev.to/michael-gokey/understanding-bem-as-a-css-methodology-for-modern-web-development-8l8"
    },
    {
      "title": "Inside the Browser Rendering Pipeline - Aleksandar Gjoreski",
      "url": "https://aleksandargjoreski.dev/blog/browser-rendering-pipeline/"
    },
    {
      "title": "Critical rendering path - Performance - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Critical_rendering_path"
    },
    {
      "title": "Is Vendor Prefixing Dead?",
      "url": "https://css-tricks.com/is-vendor-prefixing-dead/"
    },
    {
      "title": "Baseline",
      "url": "https://web.dev/baseline"
    },
    {
      "title": "How the Browser Rendering Pipeline Actually Works - DEV Community",
      "url": "https://dev.to/vishdevwork/how-the-browser-rendering-pipeline-actually-works-29n5"
    },
    {
      "title": "CSS Vendor Prefixes",
      "url": "https://bitsofco.de/css-vendor-prefixes/"
    },
    {
      "title": "Vendor prefix - Glossary - MDN Web Docs",
      "url": "https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix"
    },
    {
      "title": "Vendor prefix",
      "url": "https://developer.mozilla.org/pt-PT/docs/Web/Guide/Prefixes"
    },
    {
      "title": "Baseline (compatibility)",
      "url": "https://developer.mozilla.org/docs/Glossary/Baseline/Compatibility"
    },
    {
      "title": "Simplify Browser Compatibility Decisions with Baseline",
      "url": "https://dockyard.com/blog/09/17/2024/simplify-browser-compatibility-decisions-baseline"
    },
    {
      "title": "CSS Object Model (CSSOM)",
      "url": "https://www.w3.org/TR/cssom-1/"
    },
    {
      "title": "CSS Object Model (CSSOM)",
      "url": "https://developer.mozilla.org/en-US/docs/Glossary/CSSOM"
    },
    {
      "title": "Using dynamic styling information - Web APIs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Using_dynamic_styling_information"
    },
    {
      "title": "Using dynamic styling information - Web APIs",
      "url": "https://devdoc.net/web/developer.mozilla.org/en-US/docs/Web/Guide/DOM/Using_dynamic_styling_information.html"
    },
    {
      "title": "Window: getComputedStyle() method - Web APIs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle"
    },
    {
      "title": "Window.getComputedStyle() - Web APIs",
      "url": "https://mdn2.netlify.app/en-us/docs/web/api/window/getcomputedstyle/"
    },
    {
      "title": "CSSStyleProperties - Web APIs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleProperties"
    },
    {
      "title": "Houdini APIs",
      "url": "https://developer.mozilla.org/docs/Web/Houdini"
    },
    {
      "title": "CSS Houdini: Properties, Values, and the Paint API - Moment For Technology",
      "url": "https://www.mo4tech.com/css-houdini-properties-values-and-the-paint-api.html"
    },
    {
      "title": "Say Hello to Houdini and the CSS Paint API / Coder's Block",
      "url": "https://codersblock.com/blog/say-hello-to-houdini-and-the-css-paint-api/"
    },
    {
      "title": "The Ultimate Guide to CSS Houdini",
      "url": "https://tomquinonero.com/blog/the-ultimate-guide-to-css-houdini/"
    },
    {
      "title": "CSS Object Model (CSSOM) - Web APIs",
      "url": "https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model"
    },
    {
      "title": "Fix: Eliminate Render-Blocking CSS and JavaScript",
      "url": "https://sitegrade.io/en/common-fixes/fix-eliminate-render-blocking-css-javascript/"
    },
    {
      "title": "How to Eliminate Render-Blocking Resources (CSS and JavaScript)",
      "url": "https://nitropack.io/blog/eliminate-render-blocking-resources/"
    },
    {
      "title": "CSS Scope Proposal & Explainer - OddBird CSS Sandbox",
      "url": "https://css.oddbird.net/scope/explainer/"
    },
    {
      "title": "The End of Global CSS. CSS selectors all exist within the same…",
      "url": "https://medium.com/seek-blog/the-end-of-global-css-90d2a4a06284"
    },
    {
      "title": "Building a Scalable CSS Architecture With BEM and Utility Classes",
      "url": "https://css-tricks.com/building-a-scalable-css-architecture-with-bem-and-utility-classes/"
    },
    {
      "title": "CSS @Layer: Complete Guide to Cascade Layers",
      "url": "https://digitalthriveai.com/en-us/resources/web-development/layer/"
    },
    {
      "title": "CSS Nesting and Cascade: Elevating Web Design - DZone",
      "url": "https://dzone.com/articles/elevating-web-design-the-art-and-science-of-css-ne"
    },
    {
      "title": "Cascade Layers (@layer) in CSS: how to solve the specificity problem once and for all - DEV Community",
      "url": "https://dev.to/nickbenksim/cascade-layers-layer-in-css-how-to-solve-the-specificity-problem-once-and-for-all-3pp8"
    },
    {
      "title": "Render-blocking CSS",
      "url": "https://web.dev/articles/critical-rendering-path/render-blocking-css"
    },
    {
      "title": "How to eliminate render-blocking resources — CSS and JavaScript - LogRocket Blog",
      "url": "https://blog.logrocket.com/eliminate-render-blocking-resources-css-javascript/"
    },
    {
      "title": "Tackling Render Blocking CSS for a Fast Rendering Website — SitePoint",
      "url": "https://www.sitepoint.com/critical-rendering-path-css-fast-loading-website/"
    },
    {
      "title": "How to Eliminate Render-blocking Resources - SiteGround Academy",
      "url": "https://www.siteground.com/academy/eliminate-render-blocking-resources"
    },
    {
      "title": "Critical CSS? Not So Fast!",
      "url": "https://csswizardry.com/2022/09/critical-css-not-so-fast/"
    },
    {
      "title": "How To Fix & Eliminate Render Blocking Resources For Page Speed",
      "url": "https://pagespeedchecklist.com/eliminate-render-blocking-resources"
    },
    {
      "title": "Fix Render-Blocking CSS: 2026 Guide",
      "url": "https://webperfclinic.com/article/eliminate-render-blocking-css-critical-css-extraction-async-loading-guide"
    },
    {
      "title": "How CSS modules solve global scope in CSS",
      "url": "https://mstamstrom.medium.com/how-to-solve-the-global-scope-issue-of-css-with-css-modules-b72fe578b9fa"
    },
    {
      "title": "CSS Cascade Layers Explainer",
      "url": "https://css.oddbird.net/layers/explainer/"
    },
    {
      "title": "Cascade Layers Guide",
      "url": "https://css-tricks.com/css-cascade-layers/"
    },
    {
      "title": "CSS @scope: the end of BEM (for real this time) - Web Maker",
      "url": "https://webmaker.app/blog/css-scope-vs-bem-modules/"
    },
    {
      "title": "CSS @layer: Cascade Layers That End the Specificity Wars — W3Tweaks",
      "url": "https://www.w3tweaks.com/css/css-cascade-layers-explained/"
    },
    {
      "title": "CSS Mixins & Functions Explainer",
      "url": "https://css.oddbird.net/sasslike/mixins-functions/"
    },
    {
      "title": "CSS Functions and Mixins Module Notes",
      "url": "https://css-tricks.com/css-functions-and-mixins-module-notes/"
    },
    {
      "title": "CSS Functions and Mixins Module Notes",
      "url": "https://techreport.ngo/frontend/css-functions-and-mixins-module-notes/"
    },
    {
      "title": "Intent to Ship: CSS Custom Functions (@function)",
      "url": "https://groups.google.com/a/chromium.org/g/blink-dev/c/bvi4D7eD7wI/m/djYVLu6OAwAJ"
    },
    {
      "title": "Compatibility with the CSS custom function and mixin proposal · Issue #3787 · sass/sass",
      "url": "https://github.com/sass/sass/issues/3787"
    },
    {
      "title": "CSS Anchor Positioning and Popover API Hit Baseline 2026: The End of JavaScript Tooltip Libraries",
      "url": "https://full-net.cz/en/css-anchor-positioning-and-popover-api-hit-baseline-2026-the-end-of-javascript-tooltip-libraries/"
    },
    {
      "title": "CSS Anchor Positioning: The Complete Guide (2026)",
      "url": "https://ultimatedesigntools.com/blog/how-to-use-css-anchor-positioning/"
    },
    {
      "title": "CSS Anchor Positioning: Tooltips Without JS — CODERCOPS",
      "url": "https://blog.codercops.com/blog/css-anchor-positioning-tooltips-popovers-2026"
    },
    {
      "title": "CSS Anchor Positioning Reaches Baseline in 2026",
      "url": "https://www.refontelearning.com/blog/css-anchor-positioning-reaches-baseline"
    },
    {
      "title": "CSS Anchor Positioning: No More JavaScript for Your Tooltips and Popovers - Kevin Kenfack",
      "url": "https://kenfack.vercel.app/blog/css-anchor-positioning"
    },
    {
      "title": "CSS Anchor Positioning: Browser Support, Features, Issues",
      "url": "https://www.testmuai.com/learning-hub/css-anchor-positioning-browser-support/"
    },
    {
      "title": "CSS Cascading and Inheritance Level 6",
      "url": "https://www.w3.org/TR/css-cascade-6/"
    },
    {
      "title": "CSS Cascade 6 (Scope)",
      "url": "https://www.miriamsuzanne.com/specs/cascade-6/"
    },
    {
      "title": "[css-scoping] Proposal for light-dom scoping/namespacing with re-designed `@scope` rule · Issue #5809 · w3c/csswg-drafts",
      "url": "https://github.com/w3c/csswg-drafts/issues/5809"
    },
    {
      "title": "The Future of CSS: Cascade Layers (CSS @layer)",
      "url": "https://www.bram.us/2021/09/15/the-future-of-css-cascade-layers-css-at-layer/"
    },
    {
      "title": "PROPOSED CSS Working Group Charter",
      "url": "https://w3c.github.io/charter-drafts/2025/css-wg.html"
    },
    {
      "title": "add @mixin and @function · Issue #7301 · Fyrd/caniuse",
      "url": "https://github.com/Fyrd/caniuse/issues/7301"
    },
    {
      "title": "`@mixin` · tailwindlabs/tailwindcss · Discussion #14100",
      "url": "https://github.com/tailwindlabs/tailwindcss/discussions/14100"
    },
    {
      "title": "support for CSS Mixins & Functions · Issue #785 · web-platform-tests/interop",
      "url": "https://github.com/web-platform-tests/interop/issues/785"
    }
  ],
  "license": "https://creativecommons.org/licenses/by/4.0/"
}