Как получить унаследованные значения элемента из JavaScript

Итак, у меня есть скрипт, который получает значение свойства CSS элемента, на который нажали. Для этого я избегал window.getComputedStyle(), потому что он в основном преобразует значения rem в px и так далее... Вместо этого я использовал CSSStyleSheet.cssRules только для того, чтобы сохранить оригинальность фактически заданных единиц измерения, а не преобразовывать их.

И это отлично работает! но он не может захватить CSSRules, которые являются элементом унаследовано от родителей, поскольку стили не применяются непосредственно к элементу.

Например:

<style>
  #new {
    font-size: 2rem;
  }
</style>

<div id="new">

<h1 class="h1">This is a heading</h1>
<!––Here h1 is inheriting font-size from div that can't be catched by CSSRules––>

</div>

В этом случае getComputedStyle() работает лучше всего, так как CSSRules не удалось поймать унаследованные свойства, но опять же возникает проблема единиц, поэтому я не могу это использовать.

Или, может быть, что-то, чтобы получить метрическую единицу элемента? ?‍♀️ Тоже бы сработало!

Хотя Chrome, похоже, отлично это понял:

enter image description here

Сейчас 2022 год, и я тоже проверил другие ответы, но похоже, что никто еще не понял этого. Каково текущее решение этого? Или лучший взлом?

Редактировать1:

  • Мне нужна та же строка, которая определена пользователем в CSS. Например: calc(2rem + 1vh) И с CSSRules это работает, но не работает с наследованием, потому что оно даже не перехватывает свойство! ComputedStyle делает это, но в px я застрял здесь.

Редактировать2:

Я выбрал ответ Лайоша Арпадса в качестве принятого из-за помощи, которую я получил в комментариях (а не самого фактического ответа). Решение будет трудоемким, так что это то, что я должен сделать.

Можете ли вы также привести пример Javascript?

Lajos Arpad 23.04.2022 14:30

Просто для ясности, ваш вопрос: «Как мне получить вычисленный размер элемента в единицах, с которыми он был определен?» Я не уверен, что понимаю, почему, поскольку размер пикселя дает абсолютное измерение?

David Thomas 23.04.2022 14:30

Да @DavidThomas

Abhay Salvi 23.04.2022 14:40

Всегда ли существует такая «вещь», как «единицы, с помощью которых она была определена»? У calc(10px + 10rem + 10vw) есть небольшая проблема с знанием того, в каких единицах оно было определено - сведение всего к px кажется единственным выходом. Есть ли другой способ выразить ваше требование? например вы хотите получить ту же строку, что и в браузере (например, 10rem или calc(10rem _ 10vw) и т. д.).

A Haworth 23.04.2022 14:42

@AHaworth Я хочу получить ту же строку. Теперь CSSRules дает строку, но не работает с унаследованными элементами.

Abhay Salvi 23.04.2022 14:43

Хорошо, спасибо за разъяснение, возможно, было бы неплохо объяснить это требование более подробно в самом вопросе.

A Haworth 23.04.2022 14:46

Я повторно отредактировал вопрос. Спасибо ? @AHaworth

Abhay Salvi 23.04.2022 14:57
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
Современные подходы к организации и работе с CSS в проекте
Современные подходы к организации и работе с CSS в проекте
Любой, кто писал CSS в течение некоторого времени, знает о сложностях, которые с этим связаны, и о том, насколько это может быть болезненно.
Как использовать псевдокласс :hover в Tailwind только тогда, когда это действительно необходимо (при наличии курсора)
Как использовать псевдокласс :hover в Tailwind только тогда, когда это действительно необходимо (при наличии курсора)
Я люблю Tailwind. Раньше я относился к нему с подозрением, но как только я попробовал его использовать, я был поражен тем, сколько времени он мне...
Именование классов CSS: Конвенция именования BEM
Именование классов CSS: Конвенция именования BEM
Сопровождаемость кода, сама по себе, является пульсирующим эффектом нескольких факторов. Когда часть программного обеспечения читабельна, ясна,...
2
7
49
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете просто реализовать преобразователь пикселей в рем и использовать это:

function convertPixelsToRem(pixels) {
    return ((pixels.replace("px", "") / getComputedStyle(document.documentElement).fontSize.replace("px", "")) + "rem");
}

console.log(convertPixelsToRem(window.getDefaultComputedStyle(document.getElementById("new").querySelector(".h1"))["font-size"]));
<style>
  #new {
    font-size: 2rem;
  }
</style>
<div id="new">
  <h1 class="h1">This is a heading</h1>
  <!–– Here h1 is inheriting font-size from div ––>
</div>

РЕДАКТИРОВАТЬ

Вы можете сделать что-то вроде этого:

getOriginalRule(ruleName, ruleValue, item) {
    while (hasSameRule(item.parentNode, ruleName, ruleValue)) item = item.parentNode;
    //return the rule value based on the item via CSSStyleSheet.cssRules
}

РЕДАКТИРОВАТЬ2

В соответствии с идеями, обсуждаемыми в разделе комментариев, с целью иметь возможность собирать необработанные правила, применяемые либо напрямую, либо путем наследования к узлам, есть два основных решения:

  • можно просмотреть правила, найти элементы, к которым они применяются, а затем зациклить дерево DOM, чтобы спуститься по необработанным правилам, где они не были переопределены.
  • можно зациклить дерево DOM сверху вниз и найти все узлы, сравнить правила каждого узла с правилами его родителя и, если они отличаются, спуститься по правилам родителя

Основное различие между ними заключается в том, что первый начинает со всеми правилами CSS, а второй использует только значения.

Да! но что, если элемент использует em или vh или что-то еще?

Abhay Salvi 23.04.2022 14:42

Или - смесь!!

A Haworth 23.04.2022 14:44

@AbhaySalvi Если вы действительно хотите узнать исходную метрику, вы можете зациклить свою DOM вверх, к родителю и родителю родителя и так далее, пока правило больше не будет указано, а затем используйте cssRules, чтобы найти исходную метрику / формулу . Мне непонятна ваша цель. Насколько я понимаю, вы хотите получить значение rem. Если вместо этого вы хотите получить <любое значение метрики, которое использовал один из потомков>, вы можете зацикливать потомков вверх по иерархии, пока не найдете отправителя.

Lajos Arpad 23.04.2022 14:47

@AbhaySalvi, поэтому ваша функция будет чем-то вроде getMetricUnits(metricName, pixelValue), и вы получите значение пикселя из элемента, и вы получите метрику, используя такой цикл. getMetricUnits затем получит параметры и использует правильный преобразователь для возврата значения.

Lajos Arpad 23.04.2022 14:48

Является ли перебор родителей эффективным, а не проблемой? Что делать, если код большой? Спасибо @LajosArpad

Abhay Salvi 23.04.2022 14:51

@AbhaySalvi здесь мы говорим о HTML DOM. В этих условиях глубина 1000 будет считаться очень большой. Обратите внимание, что мы говорим не о размере фактического HTML, а о его максимальной глубине. Однако цикл из 1000 итераций не считается большим в программировании. Тем не менее, если вы выполните цикл из 1000 шагов 1000 раз, это может почувствовать пользователь.

Lajos Arpad 23.04.2022 14:53

@LajosArpad, так что в основном перебирать всех родителей - плохая идея? Или, может быть. На самом деле я пытаюсь сделать копию Chrome DevTools с точки зрения вкладки стиля. Точно так же, как они получают все значения. Я хочу знать, как они это делают или как я могу добиться того же? Просто хотел внести ясность. Спасибо за поддержку, Лайош :)

Abhay Salvi 23.04.2022 16:15

@AbhaySalvi перебирать родителей, пока не найдете источник правила, - неплохая идея. Перебор всех родителей — плохая идея, так как вы должны остановиться, как только найдете источник правила. Теперь, если вы делаете отдельный цикл для каждого атрибута, это плохо для производительности. Итак, вместо этого вы можете сделать следующее: 1. взять все интересующие вас правила и 2. зациклить родителей ровно один раз до тех пор, пока 3. вы не найдете источник всех правил, это гарантирует, что у вас есть один цикл для вашего элемента.

Lajos Arpad 23.04.2022 16:20

@AbhaySalvi Однако, если вы хотите знать все правила всех элементов, вы можете зациклить все узлы своего HTML и сопоставить каждое правило с каждым из них.

Lajos Arpad 23.04.2022 16:21

@AbhaySalvi, это предотвратит повторение одного и того же цикла родителей для братьев и сестер, поэтому это значительно повысит вашу производительность.

Lajos Arpad 23.04.2022 16:21

@AbhaySalvi, я абсолютно уверен, что DevTools работает не так. Они, безусловно, берут правила CSS, которые они получают из 1. Файлов 2. Тегов стиля 3. Атрибутов стиля 4. Программных событий, таких как изменения стиля через Javascript, и они сохраняют фактическое правило для каждого элемента во время применения правила. Итак, я уверен, что сырые правила сохраняются при их применении, однако вы работаете с уже примененными правилами, потому что внутренние события браузера вам недоступны.

Lajos Arpad 23.04.2022 16:24

@AbhaySalvi, поэтому у вас есть два основных подхода на выбор: 1. Вы можете зациклить все правила CSS, применить ко всем узлам и сохранить силу и порядок правил, а затем зациклить внутреннее дерево каждого узла, для которого есть правила, и переопределить правила узлов-потомков, если их правило имеет более низкий приоритет или 2. Начиная с корневого узла HTML, вы проходите все дерево DOM один раз (!) и всякий раз, когда вы достигаете узла, сравниваете его вычисленные правила с родительским правила. Если они эквивалентны, то ребенок унаследовал правило. Если нет, то правило отменяется.

Lajos Arpad 23.04.2022 16:28

@LajosArpad Я бы хотел, чтобы DevTools предоставил нам эту функцию, возможно, в ближайшем будущем. Спасибо за вашу помощь. Очень ценю это ?

Abhay Salvi 23.04.2022 16:28

@AbhaySalvi, единственное, чего вам нужно остерегаться, как вы уже заметили, - это размеры. Поэтому рекомендуется создать несколько HTML-кодов со странными случаями, зная, какие выходные данные правила вы ожидаете, и провести для них некоторые тесты. Помещение этих модульных тестов в iframe поможет вам сразу увидеть, что работает, а что нет. Но все идеи, описанные выше, трудозатратны. Итак, хорошая новость заключается в том, что то, что вы хотите сделать, возможно. Плохая новость заключается в том, что вам нужно проделать большую работу, чтобы достичь этого. Если мой ответ привел вас к решению, вы можете принять его как правильное.

Lajos Arpad 23.04.2022 16:31

Привет, @LajosArpad Просто хотел, чтобы ты знал, что я добился того, чего хотел, с твоей помощью! Я зациклил свой DOM вверх и получил желаемый результат. Но это не трудоемкая работа... Также я использовал библиотеку специфики, чтобы узнать, переопределяются ли стили, а также их приоритет. Огромное спасибо! ?

Abhay Salvi 24.04.2022 08:44

@AbhaySalvi отличные новости! Я рад слышать, что вы успешно нейтрализуете проблему.

Lajos Arpad 25.04.2022 13:24

Другие вопросы по теме