Shadow DOM/Web component styling in Ionic 4 - javascript

I'm trying to understand how and where ionic 4 is injecting the styling for the web components into the dom. I'm not interested in changing it via the CSS variables but I want to be able to inspect the component and see where the styling is coming from. For example on https://ionicframework.com/docs/demos/api/alert/index.html?ionic:mode=ios
If you inspect the button:
I can see the stlying being applied but I can't see where all the styling is coming from, it's not in the css bundle, style tags on the page or directly on the element or applied to the shadow-root. Normally the host styling is part of the component e.g.
So where is the :host styling being defined and how/where is it being injected into the DOM?

So as far as I know all the styles you apply to your component are usually set innerHTML. You already found the style tag which is the first tag after the component. This is super full with stylings as always thats why you usually see just a snippet. That depends on the browser but to see all the stylings you may have to do a double click into the stylings between the style tags.
Usually when I want to read something like this I copy it into my editor and take a look there:
As you can see all your stylings are defined there. Stenciljs also load some general stylings to make sure everything looks proper. These are instantiated into your head section:

So I think Ionic 4 is using: https://developers.google.com/web/updates/2019/02/constructable-stylesheets
Which is why the styling isn't visible directly in the DOM. Credit to Fraser for working this out.

Related

How to remove all inherited CSS styling on a certain page via JS in React?

I am working on a site like Codepen and we are trying to get it off the ground.
So, a user can write some code in React and then the site will display what they've written, and will also deploy it. The problem is that some of the elements have styles which are being inherited from the main site, and cannot be overridden via CSS; the only way to do it is via inline styling. Is there some sort of JS code to reset styles to default? Something like
H1.style.* = "default"
using !important works, but it would be really to be able to give the user a clean slate for CSS when they're coding...
You can see the actual notebook (as we call it) here: https://djit.su/dL22DiUPUmCf2kQMLBoAJ
As you can see, inline styling works
And also using !important works

How do detect what overrides css properties of ReactJS components?

:)
I have been developing a webpage for some time now, and I decided to use a react-calendar component from here. In the beginning, when page was lightweight it worked out of the box and, following the example on the webpage, my page rendered this:
Later on in the development, as i added more complexity to the page, calendar became completely disfigured and only displays plainly, like this:
I thought something was overriding my calendar's css properties and tried putting it outside the app div like this:
<div>
<Calendar/>
<App/>
</div>
But calendar's appearance remains unchanged. After inspecting elements in browser I noticed some suspicious crossed out values:
Is there a way of preventing parent override of calendar's css properties? Or am i missing something crucial in code which would make the calendar look neat again? It always looks neat if I install and use it in a clean project (but i'd love to have a working one everywhere :D).
Thanks in advance for your advices! :)
Have a nice day!
If you have a CSS property you can almost always override it. There is no way to tell (for example using javascript) if a css value has been overridden, since it's the browser who does this. Maybe there is something in your code that changed the behaviour by adding a parent class that overrides all its children, or a major CSS style sheet like bootstrap that overrides some others. If this is your case, it's hard to tell without looking at the code.
Good news
You can completely prevent CSS inheritance, by wrapping your component in an iframe.
Or
You can have properties that can almost never be overridden, depending on CSS specificity.
According to MDN web docs:
Inline styles added to an element (e.g., style="font-weight:bold")
always overwrite any styles in external stylesheets, and thus can be
thought of as having the highest specificity.
Have a read at the complete article to understand how it works. This statement though, says that you can always override properties if they are set inline. Now, the problem of using a third-party component is that you cannot set the styles for everything used by the component, and of course the point on using a third-party component is that you don't need to bother about these configurations.
Apart from using inline styles, you can also set the !important flag to your CSS styles, but we come to the problem of the third-party component again.
I suggest these approaches:
1) Create CSS rule to reset values to initial
Basically create a rule called NoInheritanceCalendar for example, that will reset any rules before the calendar's rules.
Set your code to:
<div className="NoInheritanceCalendar">
<Calendar/>
</div>
and in your CSS:
div.NoInheritanceCalendar {
all: initial;
}
2) Wrap it in an iframe
Although not the best approach, this is the only way you could prevent inheritance at all.
3) Copy component's style sheet, add prefix class to all properties so that they are more specific.
If your third-party component's CSS is:
.rule1 {
font ...
width ...
}
.rule2 {
font ...
width ...
}
.rule3 {
font ...
width ...
}
You can create a prefix class to make those more specific:
.MyClass.rule1 {
font ...
width ...
}
.MyClass.rule2 {
font ...
width ...
}
.MyClass.rule3 {
font ...
width ...
}
and add your component in react as:
<div className="MyClass">
<Calendar/>
</div>
These tools help you with this if it is a big style sheet:
autoprefixer
prefixfree
less-plugin-autoprefix

How to scope internal Vue application css from rest of the website?

I need to create a "plugin" that contains a user interface which will be displayed on many different vendor websites. This is a CMS agnostic plugin. I cannot use an iframe for SEO reasons. I need to isolate the plugin's css (and maybe js) from the rest of the website, and stop the rest of the website's css from getting to this plugin. How can I do this?
Update:
Ok, so I've asked a question that's a little too specific to my setup/tech. The question should have been: How do I isolate an html element from the rest of the document styles? This is answered here;
New Question: How do I scope Vue CSS so that it doesn't propagate up, but propagates to child components?
E.g I have the main Vue component which includes bootstrap.scss, i need that to apply to all child components, but I don't want it to leak into the main website. Adding scoped to style stops the leak upward, but I want it to apply to child classes as well.
Ok, I've figured it out.
Pretty simple really, combined with this answer to prevent parent -> child inheritance. I scoped all Vue css into #app { /*styles*/ } INCLUDING the bootstrap import. E.g.
<style type="text/scss" lang="scss">
#app {
#import '../node_modules/bootstrap/scss/bootstrap';
// rest of vue global styles go here.
// child components may use scoped
}
</style>
Note: I am NOT using scoped attribute on the root vue component.
I think this is what you’re looking for. In your .vue file you can add style tags to the template, then Vue will create Shadow DOM styles that only apply to your application. In the final product the styles are rendered via a data-v attribute to prevent class name conflicts.
https://vue-loader.vuejs.org/en/features/scoped-css.html
(Copied from my reddit answer)
https://www.reddit.com/r/vuejs/comments/76ss46/how_to_isolate_a_vue_application_from_the_rest_of/?st=J8UMA1JQ&sh=c3ebf5b1

Can Shadow DOM elements inherit CSS?

I was listening to this episode of JavaScript Jabber:
http://javascriptjabber.com/120-jsj-google-polymer-with-rob-dodson-and-eric-bidelman/
At one point Rob says:
And everyone has this first inclination, because it makes so much sense. You’re like, “Bootstrap is components. I’m just going to make them into tags.” But then you run into the fact that the Bootstrap style sheet is just one big long style sheet that was written assuming that it could touch every part of the document. And when you are suddenly scoping bits of the markup, scoping it so that the CSS can’t reach it, the CSS would actually have to be in the Shadow DOM with it and you would have to write that element from the ground up, that’s where people I think get really confused and really frustrated initially.
This made me wonder, how would you solve this problem with Web Components? Is there a way for Shadow DOM templates to inherit common styles, or would you have to repeat shared CSS for each separate component? Or something else?
Note: the substance of the answer below is no longer relevant, as the features discussed have been deprecated for some time. Don't use the sample code, but feel free to take a peek into the Internet past.
In a complete Shadow DOM implementation, CSS has a ::shadow pseudo-class, and also the /deep/ combinator.
The ::shadow pseudo-class lets you break into the shadow DOM under an element, and it matches the shadow root. The /deep/ combinator effectively opens up the shadow DOM completely.
Thus, if you had a <x-foo> element with <span> elements inside, you could make them red with
x-foo::shadow span { color: red; }
Or make all <spans> in any shadow DOM red:
body /deep/ span { color: red; }
Whatever hacks were necessary in the past, the current state of the shadow dom / CSS is that you can link to external stylesheets. More info at MDN: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM#Internal_versus_external_styles
You could, then, have some sort of utility stylesheet (Tailwind or similar) that all of your components reference, so you don't duplicate CSS. In theory, that CSS file would get downloaded once, cached, and then the custom elements would each be able to use the classes in it (as long as they each link to it).
Take a look at this lesser known method:
The <core-style> Polymer element
You can define the styles in an html import file:
<core-style id="x-test">
:host {
backgound-color: steelblue;
}
</core-style>
And then you can use them in more than 1 element:
<polymer-element name="x-test" noscript>
<template>
<core-style ref="x-test"></core-style>
<content></content>
</template>
</polymer-element>
In this well written article you can read more about how to use the technique.
However, a disadvantage I can think of is the impossibility of using SASS with this technique, since the styles are defined inside a <core-style> tag and not inside a <style> element, and there isn't a clear way to import an external stylesheet.
I think I understand what you ask about. You can use link in every custom element to include your main styles or extend existing element that includes it. For example (using Polymer):
<polymer-element name="ui-button" noscript>
<template>
<link rel="stylesheet" href="main.css"/>
<div class="class-from-main" style="">
<content></content>
</div>
</template>
</polymer-element>
I think it worth reading to you: https://github.com/necolas/normalize.css/issues/408
Here's one example of it working : http://jsbin.com/zayih/1/edit?html,css,output
Though it does not seem to work when targeting it with #placeholder
Turn on "Show user agent shadow DOM" in Chrome devtools config tab, then inspect the <input> to see what I mean

How do I prevent CSS interference in an injected piece of HTML?

I'm currently developing a Safari extension that uses an injected script to further inject some HTML into the current webpage, as well as injecting some other scripts to make it work. This is all working fine, but the issue is that the HTML that is injected gets affected by CSS stylesheets that the webpage has already imported. For example, the HTML looks perfect on Google.com (which has relatively little CSS styling), but awful on StackOverflow.com (which styles buttons etc).
jQuery is injected into the webpage at the time of this HTML being displayed, so I have that available. I've tried all kinds of things, including walking through all of the elements and calling removeClass() on each of them, to no avail. I've also tried to add "CSS reset" classes, etc, but nothing seems to be working.
What's the best way to go around preventing the CSS from interfering with my HTML?
You can't prevent that from happen. However, you can override the CSS rules. Give your main element a unique id (which really should be unique by obfustation, like "yourapplicationname_mainelement_name" or something), then override all possible styles that might give strange effects on your html.
Your plugin:
<div id="yourapplicationname_mainelement_name">
<p>My paragraph that must not be styled</p>
</div>
Your css:
#yourapplicationname_mainelement_name p {
display: block;
color: black;
background: white;
position: relative;
... and so on ...
}
As your css style rules are the most specific, given your id, they will override any settings present on the page where your html is injected.
Further... It might be hard to see what rules are the most important. You can use firebug or similar to understand which is overriding another. You'll have a hard time without it when developing your application.
that's a tough one. two options as I see it.
You could set a wrapping div around all your content and prefix all your css with that. example:
<body>
<div class='wrappingDiv'>
...
</div>
</body>
stylesheet:
.wrappingDiv * {}
Then when you inject jquery use that to close off the initial wrapping div before your content and to wrap any following content in the another wrapping div.
Issues:
Only possible if you are injecting
other site content onto your own
site.
This could get complicated
depending on where you are injecting
html.
The other option is to load a resetting stylesheet that targets your injected html specifically. In this case only your injected html would be wrapped but you'd need a css file that reset all attributes for all tags to their default before you add your own styles. No real issues here, just not very elegant...
Another way would be to use an element that doesn't inherit stylesheet like an iframe, but that comes with its own issues...
i have seen on different plugins that they put the code inside a iframe and they use JS to interact with the rest of the page, so you can not change the css inside.
Also i have seen that when injecting html code,people sets the style of the plugin content using the "style" attribute inside the tags so the browser will give priority to the css inside the style attribute and not the css file. The idea is to override the css,usually with the "!important" clause. But you might have some problems on different browsers
EDIT i forgot to say that my answer is on the case that you inject the code on someone's else page where you cannot control directly the css

Categories