Размер шрифта css-значения на основе Shadow DOM root
Краткое описание проблемы:
Я ищу способ установить значения размера шрифта (аналогично установке некоторого свойства в em-значение) в элементе внутри теневого dom относительно теневого хоста, независимо от размера шрифта родительского элемента в теневой дом. Что-то похожее на то, как работают rem-значения, но с тень как root вместо корня html.
Причиной этого является возможность масштабирования контента, например, виджета (который вставляется с теневым dom) в одном месте. Если свойства, основанные на размере шрифта, можно масштабировать таким образом, весь виджет можно масштабировать в каждом контексте, не устанавливая множество значений css, чтобы он соответствовал каждому местоположению.
Длинное описание проблемы:
Я ищу способ разметки текста (размер шрифта) на основе данного элемента в DOM, чтобы иметь возможность масштабировать различные части содержимого внутри этого элемента на основе этого элемента переноса (хорошо для виджетов и т.д.)., Это не только для фактического текста, часто бывает полезно наложить множество значений css на размер шрифта, поэтому элементы визуального макета масштабируются с размером текста (например, заполнение, радиус и тени). Если все основано на em-values, это может стать немного грязным. Если в элементе есть несколько уровней шрифта-шрифта, и я хочу увеличить первый уровень без изменения второго, мне нужно будет увеличить em первого уровня в dom, а уменьшить на любом элементе второго уровня (который рассчитывается на основе этого первого уровня), чтобы текст подэлементов оставался одного и того же размера. Это во многих случаях менее оптимально.
Хорошее решение базируется на Root EM (rem), поэтому изменение одного уровня dom не влияет на подэлементы. Однако, если я хочу увеличить/уменьшить размер всего текста внутри этих элементов упаковки (в одном месте), не затрагивая другие элементы на той же странице, мне нужно будет увеличить/уменьшить значения всех размеров шрифта для элементов внутри этого оберточного элемента.
Недавно я начал изучать веб-компоненты с помощью Shadow DOM и шаблонов. В тегах-шаблонах css инкапсулируется, что отлично, потому что дизайн этого окна/виджета/компонента может быть разработан самостоятельно, не задумываясь о остальной части дизайна, нежелательных унаследованных значениях и т.д. Наконец, хороший способ сделать независимые компоненты для создания веб-страницы. Но было бы здорово, если бы я мог установить своего рода размер шрифта для корневого шаблона для самого шаблона. Поэтому, если я установил некоторый элемент внутри шаблона как размер шрифта 2rem (или любой другой подобный блок), тогда размер шрифта этого элемента будет равным 2x размеру корневого шрифта шаблона, независимо от размера шрифта в хосте элемент, в котором используется этот шаблон, и независимо от размера шрифта корня страницы (элемент html).
Когда я тестировал с помощью rem-значений внутри шаблона, он все еще основывался на размере шрифта root (html tag). Я также тестировал vw-значения, но это также основано на всем видовом экране, а не только на инкапсулированной области (теневой корень).
Я просмотрел множество статей о Shadow DOM, но я не смог найти решение по этой проблеме. Любые предложения?
Что происходит (упрощенные примеры):
<html style="font-size: 16px">
<body style="font-size: 12px">
I am 12px large
<!-- em, based on the body in this case -->
<div style="font-size: 1.5em">
I am 18px large
<div style="font-size: 1.5em">
I am 27px large
</div>
</div>
<!-- rem, based on the styles of the html element -->
<div style="font-size: 1.5rem">
I am 24px large
<div style="font-size: 1.5rem">
I am 24px large
</div>
</div>
</body>
</html>
Что я хочу:
<html style="font-size: 16px">
<body style="font-size: 12px">
I am 12px large
<div style="font-size: 1.5em">
I am 18px large
</div>
<div style="font-size: 1.5rem">
I am 24px large
</div>
<template> <!-- Simulates that it is inserted into the DOM by using shadow elements -->
<style>
:root{ /* Or something like that */
font-size: 20px; /* This is the simulated "template root fontsize" */
}
</style>
<div style="font-size: 1.5trem"> <!-- Based on the template root fontsize -->
I am 30px large
<div style="font-size: 2trem">
I am 40px large
</div>
</div>
</template>
</body>
</html>
Это даст одно место (корневая часть вышеприведенного примера), чтобы управлять всеми относительными размерами шрифтов внутри этого компонента, а затем его можно объединить с не относительными размерами шрифта, такими как px или другими нормальными значениями css.
Ответы
Ответ 1
после просмотра документов веб-компонентов. Ваш пример того, что вы хотите сделать, не похож на веб-компонент. см. следующий пример веб-компонента.
в заголовке вашего документа у вас будет
<link rel="import" href="web_component_name.html"></link>
в теле, которое у вас было бы
<my-web-component>Bob</my-web-component>
ваш веб-компонент будет иметь свой собственный файл.
<html>
<template id="nameTagTemplate">
<style>
.outer {
border: 2px solid brown;
border-radius: 1em;
background: red;
font-size: 20pt;
width: 12em;
height: 7em;
text-align: center;
}
.boilerplate {
color: white;
font-family: sans-serif;
padding: 0.5em;
}
.name {
color: black;
background: white;
font-family: "Marker Felt", cursive;
font-size: 45pt;
padding-top: 0.2em;
}
</style>
<div class="outer">
<div class="boilerplate">
Hi! My name is
</div>
<div class="name">
<content></content>
</div>
</div>
</template>
<script>
var importDoc = document.currentScript.ownerDocument;
var nameBadgePrototype = Object.create(HTMLElement.prototype);
nameBadgePrototype.createdCallback = function() {
var shadow = this.createShadowRoot();
var template = importDoc.querySelector('#nameTagTemplate');
shadow.appendChild(template.content.cloneNode(true));
};
document.registerElement("my-web-component", {
prototype: nameBadgePrototype
});
</script>
</html>
Ваш пример того, что вы пытаетесь сделать и что вы действительно хотите, не соответствует. После нескольких ответов от вас я вижу, что вы хотите делать веб-компоненты. Это не то, что вы показываете в своем примере того, что вы пытаетесь сделать. Также этот код работает только в том случае, если вы включили правильные флаги в веб-браузере Chrome Canary. По умолчанию он не будет работать, и пользователь должен включить правильные настройки бета-версии для работы. Даже в интранете я бы не стал рекомендовать использовать веб-компоненты, но по-прежнему очень бета-версии, и у вас будет много проблем, поддерживающих это со многими внутренними пользователями. Пользователи постоянно находят способы reset настроек в браузере. Пользователи сломают все новое и блестящее.
Ответ 2
Селектор :host
стилирует элемент, в котором размещается теневой корень. Это имеет тот же эффект, что и стиль элемента-хозяина с внешними css/styles (например, <div id="rootelm" style="font-size:20px"></div>
для примера ниже). Если вы используете :host
вместо вашего поддельного селектора :root
, он должен работать так, как вы ожидаете. Вот пример:
<!DOCTYPE HTML>
<html style="font-size: 16px">
<body style="font-size: 12px">
I am 12px large
<div style="font-size: 1.5em">
I am 18px large
</div>
<div style="font-size: 1.5rem">
I am 24px large
</div>
<div id="rootelm"></div>
<template id="testtemplate">
<style>
:host{ /* Our new selector */
font-size: 20px; /* This is the "template root fontsize" */
}
</style>
<div style="font-size: 1em">
I am 20px large
<!-- Absolute size for comparison -->
<div style="font-size: 20px">I am 20px large as well</div>
<div style="font-size: 2em">
I am 40px large
<!-- Absolute size for comparison -->
<div style="font-size: 40px">I am 40px large as well</div>
</div>
</div>
</template>
<script>
var shadow = document.querySelector('#rootelm').createShadowRoot();
var template = document.querySelector('#testtemplate');
shadow.innerHTML = template.innerHTML;
</script>
</body>
</html>
plunker
РЕДАКТИРОВАТЬ: Обновлен плункер с JS, чтобы размер шрифта был относительно элемента, в котором размещен теневой корень. Script воспроизводится ниже.
function updateFontSizes() {
//Get root element. If you had more than one, you could use querySelectorAll(), and loop over the resulting array
var rootElm = document.querySelector("#rootelm");
/*Get styled elements. If you were using external styles instead of inline,
you'd have to use getComputedStyle or another method of getting CSS */
var styledElms = rootElm.shadowRoot.querySelectorAll('[style]');
//Get the root font size (the font size applied to the element containing the template)
var rootFontSize = window.getComputedStyle(rootElm, null).getPropertyValue("font-size");
//Format root fontsize. If you are using different units, change the string in IndexOF
rootFontSize = parseFloat(rootFontSize.substring(0, rootFontSize.indexOf('px')).trim());
for (var i = 0; i < styledElms.length; i++) {
//Get relative font size index of units
var unitIndex = styledElms[i].style.fontSize.indexOf('rem');
//Get custom attribute that we will fill later
var oldFS = styledElms[i].getAttribute("oldfs");
//if font-size contains the relative units
if (unitIndex > -1) {
//Store relative font size in custom attribute
styledElms[i].setAttribute("oldfs",styledElms[i].style.fontSize);
//Set fontsize to relative font size * computed root font size
styledElms[i].style.fontSize = parseFloat(styledElms[i].style.fontSize.substring(0, unitIndex).trim()) * rootFontSize + "px";
}
//If font size doesn't contain the relative units, and we stored the old relative font size
else if (oldFS !== null) {
//Set the fontsize to old relative font size * computed root font size
styledElms[i].style.fontSize = parseFloat(oldFS.substring(0, oldFS.indexOf('rem')).trim()) * rootFontSize + "px"
}
}
}
//Media query listeners
//See https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Testing_media_queries for more info
var mql = window.matchMedia("(max-width: 500px)");
mql.addListener(handleMediaQuery);
handleMediaQuery(mql);
function handleMediaQuery(mql) {
updateFontSizes();
}
Ответ 3
Проблема заключается в том, что вы вызываете объект DOM "теневым корнем", что у вас есть другой элемент DOM, который является ветвью корня. шаблон тега не имеет особого значения в HTML5. Нет такой вещи, как "теневой корень". Существует несколько способов ввода документа в другой документ. используя iframes, теги объектов, теги элементов. Я не рекомендую делать какие-либо из них, так как это ломает способность документа правильно обрабатываться вместе с длинным списком других будущих проблем, которые у вас будут.
Ваш лучший вариант - создать элемент DOM в CSS, который имеет базовые атрибуты, с которыми вы хотите начать, и использовать css для создания подэлементов этого элемента в зависимости от вашего css. Вы можете создать шаблон элемента DOM в css и дать ему базовый стиль.
Файл CSS
template{
font-size: 20px;
}
html файл
<template>
<div style="font-size: 1.5trem">
I am 30px large
<div style="font-size: 2trem">
I am 40px large
</div>
</div>
</template>
это установит любой элемент DOM с именем template в размер шрифта 20px, и все элементы sub dom будут меняться в зависимости от родительского элемента. также старайтесь не использовать встроенный стиль для элементов, селектор css может сделать для вас много работы.