Страницы

Поиск по вопросам

вторник, 26 ноября 2019 г.

Псевдокласс :root и работа с ним


Сегодня случайно наткнулся на примеры работы с псевдоклассом :root. Сфера применени
достаточно широкая. Хотелось бы услышать мнение тех, кто пользовался или пользуется
Реальный опыт эксплуатации, а не статейный материал. Подойдет ли для персонализации проекта, выбора основного цвета, фона и т.д.? Как дела с валидацией, скоростью и прочим? Можно ли сократить количество стилей с его помощью?

Это просто пример:



: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);
}
I am an example!
Больше примеров можно найти тут.


Ответы

Ответ 1



:root не делает ничего интересного. Его фишка в том, что он может ссылаться на любо корневой элемент. В HTML-файле это будет html, в SVG-файле svg, в XML-файле любой его корневой элемент. Но ведь мы обычно пишем стили для HTML (ну или для SVG) и мы точно знаем, какой те у нас корневой. Вот честно, мне сложно представить, чтобы мы один и тот же CSS-файл подключали одновременно к HTML и к SVG, да ещё и хотели одинаковые стили применить к их корневым элементам (но если всё-таки да, то этот псевдокласс для вас!). Так что считаю, что его вполне можно заменить селектором по тегу. Ну а если стилизуются разные XML'ки, то он вполне может быть полезен. Хотя лично я на практике не встречал необходимости стилизовать XML.

Ответ 2



Данный метод очень хорош. С помощью него можно удобно изменять стили массово. К примеру если у вас указан один и тот же цвет в нескольких стилях, то для того, что бы его поменять не нужно все перерывать. :root { --color: red; } body { margin: 0; padding: 0; } div { color: var(--color); } p { color: var(--color); } span { color: var(--color); }
Один

Два

Три По скорости ничего не могу сказать. CSS-переменные работают так же быстро, как остальные функции. По крайней мере по временной шкале браузера. Но всё же есть отзывы, что затормаживает на несколько миллисекунд. Но самая большая проблема в том, что CSS-переменные начали использоваться совсе недавно. Их не поддерживают большинство "отсталых" и почти все старые версии любых браузеров. Их не поддерживает IE, Edge, Yandex (хоть и создан на Chromium) и несколько других. Вывод мой такой: CSS-переменные нужно использовать, пока что, только в мелких разработках, для тестирования что бы было удобно потом редактировать, а в крупных проектах лучше удержаться от них Надеюсь, в будущем его будут поддерживать все браузера. Но я в любом случае не советовал бы их использовать и в будущем, так как у большинства до сих пор стоят старые версии браузеров и кто его знает, как они будет отображаться (Вспомним vw и vh, которые в разных браузерах означают разные размера).

Ответ 3



Итак, попробуем разобраться немного с некоторыми возможностями и минусами. Начать стоит именно с того, что поддержка сейчас находится на очень низком уровне Это как раз тот случай, когда некоторые браузеры вовсе не поддерживают данный псевдокласс, а значит и полноценное использование ставится под сомнение. Возможно именно из-за этого у него и нет сейчас особой популярности. Варианты использования: Самый простой пример конечно же есть в самом вопросе: :root { --main-color: #06c; --accent-color: #006; } #foo h1 { color: var(--main-color); } Задав стандартные цвета, можно использовать их во всем документе. При этом, данны способ отлично подойдет для персонализации проектов, так как изменяя одно значение, можно изменить внешний вид всей страницы. Этим же способом можно экономить и количество символов, указывая длинные стили, которые часто повторяются в документе. Например, градиент: :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; } При этом и значения в самом градиенте изменятся вместе с основным цветом. Подойдет данный псевдокласс и для работы с разными языками: :root, :root:lang(en) {--external-link: "Английский"} :root:lang(de) {--external-link: "Немецкий"} a[href^="http"]::after {content: var(--external-link) } Так же значения из CSS можно использовать и в JS. //CSS :root { --color: blue; --new-color: green; } //JS function changeDocColor() { elem.style.setProperty('--color', 'var(--new-color)'); } Другими словами, сфера применения может быть достаточно широкой. Ниже представлен пример из данного источника, в котором наглядно показана связь между элементами и различными стилями. '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; }
CSS Variable Demo

Spacing unit:

Columns:

Margins:

Red
Click the buttons on the cards to set the default color scheme for the whole sample.
Pink
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.
Purple
Use the controls above to adjust some properties that affect the entire page.
Cyan
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.
Teal
Changing the number of columns is done by recalculating the relative size of cells on the grid.
Green
Margins adjusts both the spacing around the grid and the gutters inside of it.
Подытожить хотелось бы тем же, чем и начинал. Поддержка пока не радует. Но, время идет и в скором времени все может измениться.

Ответ 4



Раз уж вопрос был на самом деле о custom properties, а не о псевдоклассе :root, то приведу несколько примеров, благодаря которым мне они понравились. Хотя препроцессоры умеют использовать свои внутренние переменные, они всё равно н умеют делать такую вещь, которая, кажется, всеми ожидалась: после изменения переменной автоматически менять имеющиеся свойства, которые её используют. Пример, унылые препроцессорные переменные, синтаксис SCSS: $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; } } Пример с модными CSS-переменными (разницу можно увидеть даже тут, если нажать н На всю страницу): :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; } }
Text inside block 1
Text inside block 1
Обратите внимание, что изменилась всего одна переменная и кучу свойств переписывать не надо, профит! Наконец-то можно разделить свойство transform, если используешь больше одной трансформаци (хотя нам уже давно обещают сделать индивидуальные свойства scale, translate и прочие). Раньше анимировать несколько свойств или перезаписать их при помощи JS было тем ещё упражнением, но теперь всё изменилось! Пример: 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); }
Отдельного упоминания заслуживает использование CSS-переменных с функцией calc() Хотя в примерах выше она уже использовалась, но, думаю, её стоит упомянуть отдельно. Особенно интересно это смотрится при создании фигур, пример (также смотреть и на весь экран): :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; } }
Коэффициенты подогнаны исходя из простейшего 3² + 4² = 5². Генерировать и менять размеры равносторонних фигур и фигур, с зависимыми друг о друга свойствами (квадраты, круги, овалы, параллелепипеды), стало просто, как никогда! ) Ну и бонус-трек, стилизация SVG-спрайта типа при помощи CSS-переменных. В автоматических генераторах спрайтов в будущем, надеюсь, будет возможность вставлять CSS-переменные каждой фигуре. .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; } P.S. на этом всё, очень жаль, что конкурс я интерпретировал как лучшее определение псевдокласса :root. Надеюсь набор этих юз-кейсов вас заинтересует. P.P.S. отметьте уже наконец ответ от @Qwertyi как принятый )

Ответ 5



Псевдокласс :root, давайте разберемся где его уместно применять и для чего он нужен. Теория Основная цель его использования, это получить доступ к корневому элементу документа. А что является корневым элементом для HTML-страницы? Это элемент . Получается, что с помощью псевдокласса :root мы будем получать доступ к нему. Вы можете сказать, а зачем мне вообще использовать псевдокласс :root, когда я могу написать так: html { background-color: #fcfcfc; } И успешно получить доступ к элементу ? Но, не стоит забывать, что CSS – это технология, которая используется не только для html-документов, ее также можно применять и к XML-страницам и SVG-файлам, и.т.д. Используя такую запись: :root { background-color: #fcfcfc; } Мы получаем более универсальную форму записи для доступа к корневому элементу страницы В условиях постоянного развития технологий и появления все новых и новых мобильных устройств – это очень важно. Вот пример документа, где это можно использовать на практике. Untitled Document

Пример документа

CSS-переменные Однако :root используется также для задания переменных в CSS. Вот здесь и начинаются настоящие чудеса: :root { --color-main: #333333; --color-alert: #ffecef; } .error { color: var(--color-alert); } Возможность использовать переменные в CSS — это значительное преимущество CSS-препроцессоров В самом простом примере, мы можем сохранить огромное количество времени определив цвет и шрифты, используемые в нашем дизайне, а затем использовать переменные, когда потребуется какой-то конкретный шрифт или цвет. Если мы решим изменить шрифт или цветовую палитру нам надо будет поменять это только в одном месте. Вывод Напоследок, хочу сказать, что псевдокласс :root появился совсем недавно и в старых браузерах он работать не будет. А поддержка :root в IE и Edge совсем удручает:

Ответ 6



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

Комментариев нет:

Отправить комментарий