Today stumbled upon examples of working with a pseudo-class :root . Scope of application is quite wide. I would like to hear the opinion of those who have used or enjoyed. Real operating experience, not article material. Is it suitable for personalizing a project, choosing a primary color, background, etc.? How are you doing with validation, speed and other things? Is it possible to reduce the number of styles with it?

This is just an example:

 :root { --main-color: #9BC53D; --secondary-color: #EBFFFA; } body { margin: 0; padding: 0; } div { position: absolute; display: flex; justify-content: center; align-items: center; right: 20%; top: 20%; left: 20%; bottom: 20%; text-align: center; background: var(--main-color); color: var(--secondary-color); } 
 <div>I am an example!</div> 

More examples can be found here .

  • association: stackoverflow.com/q/45387780/1548895 - Vadim Ovchinnikov
  • I wrote all the answers except Qwertiy , since they are about CSS variables that are not related to the selector at all :root (and the question is about this), because CSS variables can be set in any selector. - Vadim Ovchinnikov
  • @VadimOvchinnikov we already found out in the comments long ago. Nevertheless, the information in the answers to many useful, though not on the subject matter. - Alexey Giryayev
  • All information must be answered - this is a fair local rule. There is no disclaimer of questions and answers in any answer. Also, the answers themselves are strongly confused about the need to use a selector :root for CSS variables. And I do not want my colleagues to thoughtlessly use this selector, not realizing that you can do without it. - Vadim Ovchinnikov
  • @VadimOvchinnikov For this reason, the answer is exactly Qwertiy as correct. - Alexey Giryayev

6 answers 6

:root does nothing interesting. Its trick is that it can refer to any root element. In the HTML file it will be html , in the SVG svg file, in the XML file any of its root elements.

But after all, we usually write styles for HTML (well, or for SVG) and we know exactly which root tag we have. Honestly, it’s hard for me to imagine that we were connecting the same CSS file to HTML and SVG at the same time, and also wanted to apply the same styles to their root elements (but if so, yes, then this pseudo-class is for you!) .

So I think that it is quite possible to replace it with a selector for the tag.

Well, if different XMLs are being styled, then it may well be useful.
Although I personally did not see the need to stylize XML in practice.

  • You mean: root on html beech campaign read? - Vadizar
  • @VadimOvchinnikov, for what purpose is this edit made? - Qwertiy
  • @Qwertiy All abbreviations are written with a capital letter (ie, HTML, SVG, XML), so true (you can see articles about these things, they are everywhere with a capital letter), but what? - Vadim Ovchinnikov
  • And I like the little ones better. And in general, I see no point in such edits. - Qwertiy
  • @Qwertiy, I would have wrapped them in graves again :)) - Arthur

This method is very good. With it you can conveniently change styles in bulk. For example, if you have the same color in several styles, then in order to change it, you do not need to interrupt everything.

 :root { --color: red; } body { margin: 0; padding: 0; } div { color: var(--color); } p { color: var(--color); } span { color: var(--color); } 
 <div>Один</div> <p>Два</p> <span>Три</span> 

I can’t say anything by speed. CSS variables work as fast as other functions. At least in the browser timeline. But still there are reviews that slow down for a few milliseconds.

But the biggest problem is that CSS variables have been used quite recently. They do not support most of the "backward" and almost all the old versions of any browsers. They are not supported by IE , Edge , Yandex (although it was created on Chromium ) and several others.

My conclusion is:
CSS variables need to be used, so far, only in small developments, for testing, which would then be convenient to edit, and in large projects it is better to refrain from them. Hopefully in the future it will be supported by all browsers. But in any case I would not advise them to use them in the future, since the majority still have old versions of browsers and who knows how they will be displayed (Recall vw and vh , which mean different sizes in different browsers).

  • in my opinion, this answer is more related to css-variables than to :root . - Sasha Omelchenko
  • @SashaOmelchenko, I thought it was a question for him .. - Yuri
  • one
    and no! ) as for the css-variables and :root , since we are talking about them, then it seems to me just a fashionable way to set global variables, because if you write them as properties of the html tag, then the essence will not change at all. - Sasha Omelchenko
  • @SashaOmelchenko, well, I changed the answer to variables. Essentially it does not change. Well, the question on them, I think, but we'll see. - Yuri
  • one
    It seems that it will hit them. While people will enjoy the 3D space of the site, neural interfaces for ordering pizza, they will discover CSS variables. Better as VC did - when entering from a donkey, there was a direct redirect to the page with links of normal browsers. - user207618

So, let's try to understand a bit with some features and disadvantages.

We should start with the fact that support is now at a very low level. This is exactly the case when some browsers do not support this pseudo-class at all, and therefore full use is called into question. Perhaps it is because of this that he does not have much popularity now.

Use options:

The simplest example of course is in the question itself:

 :root { --main-color: #06c; --accent-color: #006; } #foo h1 { color: var(--main-color); } 

By specifying standard colors, you can use them throughout the document. At the same time, this method is perfect for personalizing projects, as by changing one value, you can change the appearance of the entire page.

The same way you can save the number of characters by specifying long styles that are often repeated in the document. For example, gradient:

 :root { --main-color: #c06; --accent-background: linear-gradient(to top, var(--main-color), white); } html, body { padding: 0; margin: 0; height: 100%; background: var(--accent-background) no-repeat; } 

At the same time, the values ​​in the gradient itself will change along with the main color.

This pseudo-class is also suitable for working with different languages:

 :root, :root:lang(en) {--external-link: "Английский"} :root:lang(de) {--external-link: "Немецкий"} a[href^="http"]::after {content: var(--external-link) } 
 <a href="http://"></a> 

The same values ​​from CSS can be used in JS.

 //CSS :root { --color: blue; --new-color: green; } //JS function changeDocColor() { elem.style.setProperty('--color', 'var(--new-color)'); } 

In other words, the scope of application can be quite wide.

Below is an example from this source , which clearly shows the relationship between elements and different styles.

 'use strict'; // Auxiliary method. Retrieves and sanitises the value of a custom property. var getVariable = function(styles, propertyName) { return String(styles.getPropertyValue(propertyName)).trim(); }; // Auxiliary method. Sets the value of a custom property at the document level. var setDocumentVariable = function(propertyName, value) { document.documentElement.style.setProperty(propertyName, value); }; // Sets the document color scheme to the color scheme of the clicked element. // This illustrates how it's easy to make a change affecting a large number of // elements by simply changing a few custom properties. var chooseDefaultColor = function(event) { // Get the styles for the event target (the clicked button), so we can see // what its custom properties are set to. var styles = getComputedStyle(event.target); // Get the values for the button's colours... var primary = getVariable(styles, '--primary-color'); var text = getVariable(styles, '--primary-color-text'); // ... and apply them to the document. setDocumentVariable('--primary-color', primary); setDocumentVariable('--primary-color-text', text); }; // Initialise page controls. window.addEventListener('load', function() { // Get the styles for the document. // This is where we've chosen to store all the global variables we use. var styles = getComputedStyle(document.documentElement); var quantum = document.getElementById('quantum'); var gutter = document.getElementById('gutter'); var columns = document.getElementById('columns'); // Set up event handlers for buttons. var buttons = document.querySelectorAll('.picker-button'); for (var i = 0; i < buttons.length; i++) { buttons[i].addEventListener('click', chooseDefaultColor); } // Retrieve initial custom property values and update controls. quantum.value = getVariable(styles, '--spacing-unit').replace('px', ''); gutter.value = getVariable(styles, '--margins'); columns.value = getVariable(styles, '--grid-columns'); // Set up event handlers for having the sliders update the custom properties // at the document level. quantum.addEventListener('input', function() { setDocumentVariable('--spacing-unit', quantum.value + 'px'); }); gutter.addEventListener('input', function() { setDocumentVariable('--margins', gutter.value); }); columns.addEventListener('input', function() { setDocumentVariable('--grid-columns', columns.value); }); }); 
 :root { /*************************** Page-wide variables ****************************/ /* Base spacing unit. */ --spacing-unit: 6px; /* Margin size. No unit, because it's a multiple of the spacing unit. */ --margins: 2; /* Colors. */ --primary-color: #5E35B1; --primary-color-text: #FFF; /* Number of columns to show. */ --grid-columns: 3; /***************************** Calculated values ****************************/ /* We don't use calc here because we don't want to resolve the values yet. You can think of these as simple textual replacements. */ /* The size of the margin around the card grid. */ --margin-size: (var(--margins) * 2); /* How much internal padding each cell should have */ --cell-padding: (4 * var(--spacing-unit)); /* How big the space between cells should be */ --grid-gutter: (var(--margins) * var(--spacing-unit)); /* How big the space should be around the grid */ --grid-margin: (var(--margin-size) * var(--spacing-unit)); /* Calculated cell margin */ --cell-margin: (var(--grid-gutter) / 2); } .header { display: block; position: relative; height: calc(28 * var(--spacing-unit)); /* Use a default value for the background color, by passing it in as the 2nd parameter to var(). We don't strictly need it in this case, since we've defined it at the document level, but this illustrates common usage. */ background-color: var(--primary-color, #5E35B1); padding-left: calc(4 * var(--spacing-unit)); transition: background-color 1s; } .title { position: relative; top: calc(8 * var(--spacing-unit)); font-family: 'Roboto', 'Helvetica', sans-serif; font-size: calc(4 * var(--spacing-unit)); font-weight: 400; color: var(--primary-color-text); transition: color 1s; } .shade { display: block; box-sizing: border-box; position: absolute; padding-left: calc(1 * var(--spacing-unit)); bottom: 0; left: 0; width: 100%; height: calc(8 * var(--spacing-unit)); background-color: rgba(0, 0, 0, 0.2); } .grid { /* Resets */ margin: 0; border: 0; padding: 0; display: flex; flex-flow: row wrap; align-items: stretch; padding: calc(var(--grid-margin) - var(--cell-margin)); background-color: var(--grid-color); } .cell { font-family: 'Roboto', 'Helvetica', sans-serif; color: rgb(97, 97, 97); display: flex; flex-direction: column; box-sizing: border-box; margin: calc(var(--cell-margin)); background-color: var(--cell-color); width: calc(100% / var(--grid-columns) - var(--grid-gutter)); box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12); } .cell-title { font-size: calc(3 * var(--spacing-unit)); } .cell-header { display: flex; align-items: center; color: var(--primary-color-text); box-sizing: border-box; background-color: var(--primary-color); padding-left: calc(var(--cell-padding)); height: calc(12 * var(--spacing-unit)); } .cell-content { font-size: calc(2.5 * var(--spacing-unit)); padding: calc(var(--cell-padding)); flex-grow: 1; } .cell-actions { padding: calc(2 * var(--spacing-unit)); border-top: 1px solid rgba(0, 0, 0, 0.12); } .picker-button { position: relative; font-family: 'Roboto', 'Helvetica', sans-serif; font-size: calc(2 * var(--spacing-unit)); display: inline-block; box-sizing: border-box; border: none; border-radius: 2px; color: var(--primary-color); text-decoration: none; padding: calc(2 * var(--spacing-unit)); text-decoration: none; background: transparent; cursor: pointer; overflow: hidden; text-transform: uppercase; transition: background-color 0.2s; } .picker-button:focus { outline: none; } .picker-button:active { background-color: #DDD; } .controls { display: flex; flex-direction: column; position: absolute; top: 4px; right: 4px; font-family: sans-serif; font-size: 12px; padding: 8px; background-color: rgba(200, 200, 200, 0.8); } .control { display: flex; align-items: center; margin: 0 0 8px 0; } .control-key { flex-grow: 1; margin-right: 16px; } .control-value { width: 152px; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="header"> <div class="title">CSS Variable Demo</div> <div class="shade"></div> <div class="controls"> <p class="control"> <span class="control-key">Spacing unit:</span> <input class="control-value" type="range" id="quantum" min="4" max="8" step="1"> </p> <p class="control"> <span class="control-key">Columns:</span> <input class="control-value" type="range" id="columns" min="1" max="4" step="1"> </p> <p class="control"> <span class="control-key">Margins:</span> <input class="control-value" type="range" id="gutter" min="1" max="5" step="1"> </p> </div> </div> <div class="grid"> <div class="cell" style="--primary-color: #F44336; --primary-color-text: #FFF;"> <header class="cell-header"> <div class="cell-title"> Red </div> </header> <main class="cell-content"> Click the buttons on the cards to set the default color scheme for the whole sample. </main> <div class="cell-actions"> <button class="picker-button"> Use this color <div class="ripple"></div> </button> </div> </div> <div class="cell" style="--primary-color: #E91E63; --primary-color-text: #FFF;"> <header class="cell-header"> <div class="cell-title"> Pink </div> </header> <main class="cell-content"> The colors on the cards are not affected because they're individually defined at the card level, and thus prioritised according to standard CSS rules. </main> <div class="cell-actions"> <button class="picker-button"> Use this color <div class="ripple"></div> </button> </div> </div> <div class="cell" style="--primary-color: #9C27B0; --primary-color-text: #FFF;"> <header class="cell-header"> <div class="cell-title"> Purple </div> </header> <main class="cell-content"> Use the controls above to adjust some properties that affect the entire page. </main> <div class="cell-actions"> <button class="picker-button"> Use this color <div class="ripple"></div> </button> </div> </div> <div class="cell" style="--primary-color: #00BCD4; --primary-color-text: #424242;"> <header class="cell-header"> <div class="cell-title"> Cyan </div> </header> <main class="cell-content"> Every size on the page is calculated as a multiple of the spacing unit, so setting the property to a different value resizes all elements. </main> <div class="cell-actions"> <button class="picker-button"> Use this color <div class="ripple"></div> </button> </div> </div> <div class="cell" style="--primary-color: #009688; --primary-color-text: #FFF;"> <header class="cell-header"> <div class="cell-title"> Teal </div> </header> <main class="cell-content"> Changing the number of columns is done by recalculating the relative size of cells on the grid. </main> <div class="cell-actions"> <button class="picker-button"> Use this color <div class="ripple"></div> </button> </div> </div> <div class="cell" style="--primary-color: #4CAF50; --primary-color-text: #424242;"> <header class="cell-header"> <div class="cell-title"> Green </div> </header> <main class="cell-content"> Margins adjusts both the spacing around the grid and the gutters inside of it. </main> <div class="cell-actions"> <button class="picker-button"> Use this color <div class="ripple"></div> </button> </div> </div> </div> 

I would like to summarize what I started. Support is not happy. But time goes on and soon everything can change.

  • Thanks for your reply. In general, I did not see anything new, and all the examples are from the network. But at least in your own words everything is stated. Plus, once again confirmed my thoughts that now especially nobody uses this solution. - Alexey Giryayev

Since the question was actually about custom properties, and not about the pseudo-class :root , I’ll give you a few examples by which I liked them.

Although preprocessors are able to use their internal variables, they still do not know how to do such a thing, which seems to be expected by everyone: after changing a variable, automatically change the existing properties that use it. Example, dull preprocessing variables, SCSS syntax:

 $main-index: 20px; .block { padding: $main-index; } .block-number-2 { font-size: $main-index; } @media (max-width: 900px) { $main-index: 20px; /* хотелось бы не задавать заново все свойства, но придётся :( */ .block { padding: $main-index; } .block-number-2 { font-size: $main-index; } } 

An example of fashionable CSS variables (the difference can be seen even here, if you click on Full page ):

 :root { --main-index: 20px; } div { width: calc(var(--main-index) * 10); height: calc(var(--main-index) * 8); border: 1px solid; } .block { padding: var(--main-index); } .block-number-2 { font-size: var(--main-index); } @media (max-width: 900px) { :root { --main-index: 10px; } } 
 <div class=block>Text inside block 1</div> <div class=block-number-2>Text inside block 1</div> 

Please note that only one variable has changed and you do not need to rewrite a bunch of properties, profit!


Finally, you can separate the transform property if you use more than one transformation (although we have long been promised to make the individual properties scale , translate and others). Earlier, animating several properties or rewriting them using JS was another exercise, but now everything has changed! Example:

 var block = document.querySelector('.transformator'), bodyStyles = window.getComputedStyle(document.body), scale = bodyStyles.getPropertyValue('--scale'), trX = bodyStyles.getPropertyValue('--trX'), trY = bodyStyles.getPropertyValue('--trY'), rotation = bodyStyles.getPropertyValue('--rotation'); document.querySelector('.controller').onclick = function(e) { if ( e.target.classList.contains('scale') ) { scale *= 1.1; block.style.setProperty('--scale', scale); } else if ( e.target.classList.contains('rotate') ){ rotation = parseInt(rotation) + 15 + 'deg'; block.style.setProperty('--rotation', rotation); } else if ( e.target.classList.contains('movex') ){ trX = parseInt(trX) + 10 + 'px'; block.style.setProperty('--trX', trX); } else if ( e.target.classList.contains('movey') ){ trY = parseInt(trY) + 10 + 'px'; block.style.setProperty('--trY', trY); } } 
 :root { --trX: 0; --trY: 0; --rotation: 0deg; --scale: 1; --base: 50px; } .transformator { width: var(--base); height: var(--base); background-image: linear-gradient(#2196f3 0%, #2196f3 50%, #ff0 50%); /* Slava Ukraini! */ transform: scale(var(--scale)) translate3d(var(--trX), var(--trY), 0) rotate(var(--rotation)); transition: transform .5s; } .controller { margin-bottom: var(--base); } 
 <div class=controller> <button class=scale>scale +10%</button> <button class=rotate>rotate 15 deg</button> <button class=movex>move X +10px</button> <button class=movey>move Y +10px</button> </div> <div class=transformator></div> 


Special mention deserves the use of CSS-variables with the function calc() . Although in the examples above it has already been used, but I think it should be mentioned separately. This is especially interesting when creating figures, an example (also look at the whole screen):

 :root { --start-index: 3; --a: calc( var(--start-index) * 20px); --b: calc( (var(--start-index) + var(--start-index) / 3) * 20px); --c: calc( (var(--start-index) + (var(--start-index) / 3) * 2) * 20px); } .pythagorean-triangle { position: relative; width: var(--b); height: var(--a); } .pythagorean-triangle div { height: 1px; background-color: #000; position: absolute; top: 0; left: 0; } .pythagorean-triangle__a { width: var(--a); transform: rotate(90deg); transform-origin: 0 0; } .pythagorean-triangle__b { width: var(--b); } .pythagorean-triangle__c { width: var(--c); left: auto !important; right: 0; transform: rotate(-36.8deg); transform-origin: 100% 0; } @media (min-width: 900px) { :root { --start-index: 30; } } 
 <div class=pythagorean-triangle> <div class=pythagorean-triangle__a></div> <div class=pythagorean-triangle__b></div> <div class=pythagorean-triangle__c></div> </div> 

The coefficients are adjusted on the basis of the simplest 3² + 4² = 5².

It became easy to generate and resize equilateral figures and figures with properties dependent on each other (squares, circles, ovals, parallelepipeds)! )


Well, and a bonus track, stylization SVG-sprite type <use> using CSS-variables. In the automatic generator of sprites in the future, I hope, it will be possible to insert CSS variables for each shape.

 .sprite { display: none; } .cross { display: inline-block; vertical-align: top; width: 100px; height: 200px; } .cross--red { --one-color: red; --two-color: #9a1616; } .cross--green { --one-color: green; --two-color: #5ef636; } .cross--blue { --one-color: blue; --two-color: #4666d5; } 
 <svg xmlns="http://www.w3.org/2000/svg" class=sprite> <g id="icon"> <rect width="100" height="10" x="0" y="40" style="fill: var(--one-color, #000)"/> <rect width="10" height="200" x="45" y="0" style="fill: var(--two-color, #000)" /> </g> </svg> <svg xmlns="http://www.w3.org/2000/svg" class="cross"> <use xlink:href="#icon"/> </svg> <svg xmlns="http://www.w3.org/2000/svg" class="cross cross--red"> <use xlink:href="#icon"/> </svg> <svg xmlns="http://www.w3.org/2000/svg" class="cross cross--green"> <use xlink:href="#icon"/> </svg> <svg xmlns="http://www.w3.org/2000/svg" class="cross cross--blue"> <use xlink:href="#icon"/> </svg> 

PS that's all, very sorry that I interpreted the contest as the best definition of a pseudo-class :root . I hope the set of these juz-cases will interest you.

PPS tick off finally the answer from @Qwertyi as accepted)

  • Thank. First I wanted to mark your answer, but, nevertheless. Based on the question, the most correct answer would be Qwertyi. However, I wanted to hear exactly your answer. It is a pity that I have already chosen a competitive question. - Alexey Giryayev
  • @AlexeyGiryayev try to write to the admins, theoretically they can rearrange the award) - Sasha Omelchenko
  • And how to write to admins? - Alexey Giryayev
  • @AlexeyGiryayev, for example, in chat chat.stackexchange.com/rooms/22462/stack-overflow-- chat NicolasChabanovsky or NickVolynkin via @ - Sasha Omelchenko
  • @SashaOmelchenko no, we can not rearrange. - Nick Volynkin

Pseudo-class :root , let's figure out where to use it appropriately and what it is for.

Theory

The main purpose of its use is to gain access to the root element of the document.

And what is the root element for an HTML page? This is the <html> element. It turns out that with the help of the pseudo-class: root we will get access to it.

You can say, why should I even use the pseudo-class: root, when I can write this:

 html { background-color: #fcfcfc; } 

And successfully access the item?

But do not forget that CSS is a technology that is used not only for html documents, it can also be applied to XML pages and SVG files, etc.

Using this entry:

 :root { background-color: #fcfcfc; } 

We get a more universal form of entry to access the root element of the page. With the constant development of technology and the emergence of new and new mobile devices - this is very important.

Here is an example document where this can be used in practice.

 <!DOCTYPE HTML> <html> <head> <style type="text/css"> :root {background-color:#000; } p {color:#fff;} </style> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Untitled Document</title> </head> <body> <p>Пример документа</p> </body> </html> 

CSS Variables

However :root is also used to set variables in CSS. This is where the real miracles begin:

 :root { --color-main: #333333; --color-alert: #ffecef; } .error { color: var(--color-alert); } 

The ability to use variables in CSS is a significant advantage of CSS preprocessors. В самом простом примере, мы можем сохранить огромное количество времени определив цвета и шрифты, используемые в нашем дизайне, а затем использовать переменные, когда потребуется какой-то конкретный шрифт или цвет. Если мы решим изменить шрифт или цветовую палитру нам надо будет поменять это только в одном месте.

Conclusion

Напоследок, хочу сказать, что псевдокласс :root появился совсем недавно и в старых браузерах он работать не будет. А поддержка :root в IE и Edge совсем удручает :

enter image description here

  • 2
    а что мешает задавать базовые значения цсс-переменных не в :root , а в html ?Sasha Omelchenko
  • five
    "Напоследок, хочу сказать, что псевдокласс :root появился совсем недавно и в старых браузерах он работать не будет. А поддержка :root в IE и Edge совсем удручает:" и привёл скриншот для css-переменных. Сам по себе :root согласно caniuse поддерживается в IE9+.Qwertiy
  • one
    @AlexeyGiryayev вы бы определились о чем вопрос — о псевдоклассе :root или о кастом пропертис ака цсс-переменных.Sasha Omelchenko
  • one
    @AlexeyGiryayev конечно! jsfiddle.net/yh1egu7sSasha Omelchenko
  • one
    @SashaOmelchenko в общем-то, теперь все встало на свои места, а ответ Qwertiy был наиболее правильным. Просто из просторов интернета не было понятно, что это 2 разных понятия. Спасибо вам.Alexey Giryayev

Реальный опыт эксплуатации именно :root - только для написания стилей под конкретный браузер. browser strangeness . Работает как раз благодаря тому, что не все его поддерживают.