Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Font size css-values based on Shadow DOM root

Short description of issue:

I am looking for a way to set font size based values (similar to setting some property to an em-value) in an element inside a shadow dom relative to the shadow host, regardless of font size of the parent element in the shadow dom. Something similar to how rem-values work, but with the shadow as root instead of the html root.

The reason for this is to be able to scale content like a widget (that is inserted with shadow dom) in one place. If properties that is based on font size can be scaled this way, a whole widget can be scaled in every context without having to set a lot of css values to make it fit at every location.

Long description of issue:

I am looking for a way to size text (font-size) based on a given element in the DOM, to be able to scale different parts of content inside that element based on this wrapping element (good for widgets and such). This is not only for the actual text, there is often good to base a lot of css values on font-size, so the elements visual layout scale with the size of the text (like padding, border-radius and shadows). If everything is based on em-values, this can get a little messy. If there is multiple levels of inheritance of font-sizes inside the element, and I want to enlarge the first level without changing the second, I would need to enlarge the em of the first level in the dom, while reducing on any second level element (that is calculated based on that first level) to make text of sub-elements remain the same size. This is less than optimal in many cases.

A nice solution is basing stuff on Root EM (rem), so changing one level of the dom does not affect the sub-elements. However, if I want to enlarge/reduce the size of all text inside this wrapping elements (in one place) without affecting the other elements on the same page, I would need to enlarge/reduce the rem-values of all font-sizes for elements inside that wrapping element.

I recently started looking into Web Components with Shadow DOM and templates. In template-tags, css is encapsulated which is great because the design of that box/widget/component can be styled on its own without having to think of the rest of the design, unwanted inherited values and such. Finally a good way to make independent components to build up a webpage. But there would be great if I could set a kind of template root font-size for the template itself. So if I set some element inside the template to be font-size 2rem (or any other similar unit), then the font-size of that element would be 2x the root font size of the template, regardless of the font size in the host element where that template is used, and regardless of the font-size of the root of the page (the html element).

When I tested with rem-values inside a template, it was still based on the page root (html tag) font-size. I have also tested vw-values but this is also based on the whole viewport, and not just the encapsulated area (the shadow root).

I have looked at lots of articles about Shadow DOM, but I have not been able to find any solution on this issue. Any suggestions?

What happens (simplified examples):

<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>

What I want:

<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>

This would give one place (the :root part of the example above) to control all relative font-sizes inside that component, and this can then be combined with non-relative font-sizes like px or other normal css values.

like image 887
henit Avatar asked Jul 25 '14 10:07

henit


People also ask

Does shadow DOM inherit CSS?

Nope! As written in the spec: The top-level elements of a shadow tree inherit from their host element. What this means is that inheritable styles, like color or font-family among others, continue to inherit in shadow DOM, will pierce the shadow DOM and affect your component's styling.

What is the font size of root element?

The default root font size of HTML is 16px.

How to use custom CSS in Shadow DOM?

Custom CSS properties pierce through shadow DOM, they are visible everywhere, so the inner .field rule will make use of it. Shadow DOM can include styles, such as <style> or <link rel="stylesheet">. slotted elements (coming from light DOM), ::slotted (selector) allows to select slotted elements themselves, but not their children.

Do styles leak in Shadow DOM?

Like an <iframe>, selectors and styles inside of a shadow DOM node don’t leak outside of the shadow root and styles from outside the shadow root don’t leak in. There are a few exceptions that inherit from the parent document, like font family and document font sizes (e.g. rem) that can be overridden internally.

How do I style a shadow node in HTML?

Currently, the only reliable way to style a shadow DOM node is by adding a <style> element to the shadow root’s inner HTML. This works fine in almost every case as browsers will de-duplicate stylesheets across these components, where possible.

What is Shadow DOM?

For example… Styles can be applied using HTML element selectors like <button> and <div>. These styles could break a component. Shadow DOM is the only thing that offers ( almost) full encapsulation — you can rest assured that your component will look the same, even in a messy !important strewn codebase because each component is encapsulated.


1 Answers

after reviewing the Web Component documents. Your example of what you want to do looks nothing like a web component. see the following Web Component example.

in the header of your document you would have

<link rel="import" href="web_component_name.html"></link> 

in the body you would have

<my-web-component>Bob</my-web-component> 

your web component would then have its own file.

<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> 

Your example of what you're attempting to do and what you really want do not match. After a few replies from you I see you want to do Web Components. This is not what you where showing in your example of what you are attempting to do. Also this code only works if you have enabled the right flags in your Chrome Canary web browser. It will not work by default and needs the user to enable the correct beta settings for it to work. Even in an intranet I would not recommend using web components yet as it's still very much beta and you will have a lot of problems maintaining this with many internal users. Users find ways to reset the settings on the browser all the time. Users break everything new and shiny.

like image 155
Patrick W. McMahon Avatar answered Sep 23 '22 09:09

Patrick W. McMahon