Prevent from applying both styles [duplicate] - css

I wrote a Google Chrome extension, which popups a dialog with an autocomplete field and it's own style, but there are some sites where my CSS gets totally broken, which doesn't look very nice.
I know about isolating styles with iFrames, but in Google Chrome extension there is no way to isolate my HTML and CSS in this way. Another method is to wrap all my stuff into a separated div with it's own id and relative styles for that id, and I do so, but it seems that it doesn't work on some sites with "hard" tags style overloading or "!important" directives in the CSS code.
So, I want to know is there any way to really isolate my styles in z convenient way or it's my bad carma to overload every little CSS property to fix one or another style issue for each site?
By the way: I set up my manifest to load all the things at the "document_end", but I see it's not being applied to the stylesheets which is every time loaded whenever the DOM is ready.

At the time of asking the question, your only option was to either use iframes, or stylesheets with a very high specificity and explicitly set all properties that might affect styles. The last method is very cumbersome, because there will always be some property that is overlooked by you. Consequently, the only usable method for isolating stylesheets was to use iframes.
The solution to this problem -isolation of styles without iframes- is Shadow DOM (since Chrome 25). You can find a tutorial at HTML5 Rocks. For a real-world Chrome extension that uses Shadow DOM to isolate styles, see Display #Anchors (source code here).

As I've recently gone through the gauntlet of this issue, I want to share some information I think is valuable.
First, Rob W's answer is correct. Shadow DOM is the correct solution to this problem. However, in my case not only did I need CSS isolation, I also needed JavaScript events. For example, what happens if the user clicks a button that lives within the isolated HTML? This gets really ugly with just Shadow DOM, but we have another Web Components technology, Custom Elements, to the rescue. Except that as of this writing there is a bug in chrome that prevents custom element in chrome extensions. See my questions here and here and the bug here.
So where does that leave us? I believe the best solution today is IFrames, which is what I went with. The article shahalpk linked is great but it only describes part of the process. Here's how I did it:
First, create an html file and js file for your isolated widget. Everything inside these files will run in an isolated environment in an iframe. Be sure to source your js file from the html file.
//iframe.js
var button = document.querySelector('.my-button');
button.addEventListener('click', function() {
// do useful things
});
//iframe.html
<style>
/* css */
</style>
<button class='my-button'>Hi there</button>
<script src='iframe.js'></script>
Next, inside your content script create an iframe element in javascript. You need to do it in javascript because you have to use chrome.extension.getURL in order to grab your iframe html file:
var iframe = document.createElement('iframe');
iframe.src = chrome.extension.getURL("iframe.html");
document.body.appendChild(iframe);
And that's it.
One thing to keep in mind: If you need to communicated between the iframe and the rest of the content script, you need to chrome.runtime.sendMessage() to the background page, and then chrome.tabs.sendMessage from the background page back to the tab. They can't communicate directly.
EDIT: I wrote a blog post detailing everything I learned through my process, including a complete example chrome extension and lots of links to different information:
https://apitman.com/3/#chrome-extension-content-script-stylesheet-isolation
In case my blog goes down, here's the sources to the original post:
Blog post
Example source

Either use all
.some-selector {
all: initial;
}
.some-selector * {
all: unset;
}
or use Shadow DOM
Library
function Widget(nodeName, appendTo){
this.outer = document.createElement(nodeName || 'DIV');
this.outer.className = 'extension-widget-' + chrome.runtime.id;
this.inner = this.outer.createShadowRoot();
(appendTo || document.body).appendChild(this.outer);
}
Widget.prototype.show = function(){
this.outer.style.display = 'block';
return this;
};
Widget.prototype.hide = function(){
this.outer.style.display = 'none';
return this;
};
Usage
var myWidget = new Widget();
myWidget.inner.innerHTML = '<h1>myWidget</h1>';
You can access the widget contents via myWidget.inner and the outer via myWidget.outer.
Styles
/*
* Reset Widget Wrapper Element
*/
.extension-widget-__MSG_##extension_id__ {
background: none;
border: none;
bottom: auto;
box-shadow: none;
color: black;
cursor: auto;
display: inline;
float: none;
font-family : "Helvetica Neue", "Helvetica", "Arial", sans-serif;
font-size: inherit;
font-style: normal;
font-variant: normal;
font-weight: normal;
height: auto;
left: auto;
letter-spacing: 0;
line-height: 100%;
margin: 0;
max-height: none;
max-width: none;
min-height: 0;
min-width: 0;
opacity: 1;
padding: 0;
position: static;
right: auto;
text-align: left;
text-decoration: none;
text-indent: 0;
text-shadow: none;
text-transform: none;
top: auto;
vertical-align: baseline;
white-space: normal;
width: auto;
z-index: 2147483648;
}
/*
* Add your own styles here
* but always prefix them with:
*
* .extension-widget-__MSG_##extension_id__
*
*/
.extension-widget-__MSG_##extension_id__{
position: fixed;
top: 100px;
margin: 0 auto;
left: 0;
right: 0;
width: 500px;
}
.extension-widget-__MSG_##extension_id__::shadow h1 {
display: block;
margin: 0 auto;
padding: 20px;
background-color: yellow;
border: 10px solid green;
font-size: 20px;
text-align: center;
}

I recently created Boundary, a CSS+JS library to solve problems just like this. Boundary creates elements that are completely separate from the existing webpage's CSS.
Take creating a dialog for example. After installing Boundary, you can do this in your content script
var dialog = Boundary.createBox("yourDialogID", "yourDialogClassName");
Boundary.loadBoxCSS("#yourDialogID", "style-for-elems-in-dialog.css");
Boundary.appendToBox(
"#yourDialogID",
"<button id='submit_button'>submit</button>"
);
Boundary.find("#submit_button").click(function() {
// some js after button is clicked.
});
Elements within #yourDialogID will not be affected by the existing webpage. And find() function returns a regular jQuery DOM element so you can do whatever you want with it.
Hope this helps. Please let me know if you have any question.
https://github.com/liviavinci/Boundary

Use iframes. It's a workaround, but works fine.
Maxime has written an article on it.

Related

React Widget's CSS breaking due to the hindrance caused by CSS of the background site [duplicate]

I wrote a Google Chrome extension, which popups a dialog with an autocomplete field and it's own style, but there are some sites where my CSS gets totally broken, which doesn't look very nice.
I know about isolating styles with iFrames, but in Google Chrome extension there is no way to isolate my HTML and CSS in this way. Another method is to wrap all my stuff into a separated div with it's own id and relative styles for that id, and I do so, but it seems that it doesn't work on some sites with "hard" tags style overloading or "!important" directives in the CSS code.
So, I want to know is there any way to really isolate my styles in z convenient way or it's my bad carma to overload every little CSS property to fix one or another style issue for each site?
By the way: I set up my manifest to load all the things at the "document_end", but I see it's not being applied to the stylesheets which is every time loaded whenever the DOM is ready.
At the time of asking the question, your only option was to either use iframes, or stylesheets with a very high specificity and explicitly set all properties that might affect styles. The last method is very cumbersome, because there will always be some property that is overlooked by you. Consequently, the only usable method for isolating stylesheets was to use iframes.
The solution to this problem -isolation of styles without iframes- is Shadow DOM (since Chrome 25). You can find a tutorial at HTML5 Rocks. For a real-world Chrome extension that uses Shadow DOM to isolate styles, see Display #Anchors (source code here).
As I've recently gone through the gauntlet of this issue, I want to share some information I think is valuable.
First, Rob W's answer is correct. Shadow DOM is the correct solution to this problem. However, in my case not only did I need CSS isolation, I also needed JavaScript events. For example, what happens if the user clicks a button that lives within the isolated HTML? This gets really ugly with just Shadow DOM, but we have another Web Components technology, Custom Elements, to the rescue. Except that as of this writing there is a bug in chrome that prevents custom element in chrome extensions. See my questions here and here and the bug here.
So where does that leave us? I believe the best solution today is IFrames, which is what I went with. The article shahalpk linked is great but it only describes part of the process. Here's how I did it:
First, create an html file and js file for your isolated widget. Everything inside these files will run in an isolated environment in an iframe. Be sure to source your js file from the html file.
//iframe.js
var button = document.querySelector('.my-button');
button.addEventListener('click', function() {
// do useful things
});
//iframe.html
<style>
/* css */
</style>
<button class='my-button'>Hi there</button>
<script src='iframe.js'></script>
Next, inside your content script create an iframe element in javascript. You need to do it in javascript because you have to use chrome.extension.getURL in order to grab your iframe html file:
var iframe = document.createElement('iframe');
iframe.src = chrome.extension.getURL("iframe.html");
document.body.appendChild(iframe);
And that's it.
One thing to keep in mind: If you need to communicated between the iframe and the rest of the content script, you need to chrome.runtime.sendMessage() to the background page, and then chrome.tabs.sendMessage from the background page back to the tab. They can't communicate directly.
EDIT: I wrote a blog post detailing everything I learned through my process, including a complete example chrome extension and lots of links to different information:
https://apitman.com/3/#chrome-extension-content-script-stylesheet-isolation
In case my blog goes down, here's the sources to the original post:
Blog post
Example source
Either use all
.some-selector {
all: initial;
}
.some-selector * {
all: unset;
}
or use Shadow DOM
Library
function Widget(nodeName, appendTo){
this.outer = document.createElement(nodeName || 'DIV');
this.outer.className = 'extension-widget-' + chrome.runtime.id;
this.inner = this.outer.createShadowRoot();
(appendTo || document.body).appendChild(this.outer);
}
Widget.prototype.show = function(){
this.outer.style.display = 'block';
return this;
};
Widget.prototype.hide = function(){
this.outer.style.display = 'none';
return this;
};
Usage
var myWidget = new Widget();
myWidget.inner.innerHTML = '<h1>myWidget</h1>';
You can access the widget contents via myWidget.inner and the outer via myWidget.outer.
Styles
/*
* Reset Widget Wrapper Element
*/
.extension-widget-__MSG_##extension_id__ {
background: none;
border: none;
bottom: auto;
box-shadow: none;
color: black;
cursor: auto;
display: inline;
float: none;
font-family : "Helvetica Neue", "Helvetica", "Arial", sans-serif;
font-size: inherit;
font-style: normal;
font-variant: normal;
font-weight: normal;
height: auto;
left: auto;
letter-spacing: 0;
line-height: 100%;
margin: 0;
max-height: none;
max-width: none;
min-height: 0;
min-width: 0;
opacity: 1;
padding: 0;
position: static;
right: auto;
text-align: left;
text-decoration: none;
text-indent: 0;
text-shadow: none;
text-transform: none;
top: auto;
vertical-align: baseline;
white-space: normal;
width: auto;
z-index: 2147483648;
}
/*
* Add your own styles here
* but always prefix them with:
*
* .extension-widget-__MSG_##extension_id__
*
*/
.extension-widget-__MSG_##extension_id__{
position: fixed;
top: 100px;
margin: 0 auto;
left: 0;
right: 0;
width: 500px;
}
.extension-widget-__MSG_##extension_id__::shadow h1 {
display: block;
margin: 0 auto;
padding: 20px;
background-color: yellow;
border: 10px solid green;
font-size: 20px;
text-align: center;
}
I recently created Boundary, a CSS+JS library to solve problems just like this. Boundary creates elements that are completely separate from the existing webpage's CSS.
Take creating a dialog for example. After installing Boundary, you can do this in your content script
var dialog = Boundary.createBox("yourDialogID", "yourDialogClassName");
Boundary.loadBoxCSS("#yourDialogID", "style-for-elems-in-dialog.css");
Boundary.appendToBox(
"#yourDialogID",
"<button id='submit_button'>submit</button>"
);
Boundary.find("#submit_button").click(function() {
// some js after button is clicked.
});
Elements within #yourDialogID will not be affected by the existing webpage. And find() function returns a regular jQuery DOM element so you can do whatever you want with it.
Hope this helps. Please let me know if you have any question.
https://github.com/liviavinci/Boundary
Use iframes. It's a workaround, but works fine.
Maxime has written an article on it.

Hide SCM player in tumblr

I need an extra help with this, i'm just learning to code, already found this preview question but i don't understand completly how the css file must be done and upload. Or if any other way to do the same.
This is my page and this is the code that SCM provides
!-- SCM Music Player http://scmplayer.net -->
<script type="text/javascript" src="https://www.scmplayer.net/script.js"
data-config="{'skin':'skins/black/skin.css','volume':50,'autoplay':true,'shuffle':false,'repeat':1,'placement':'top','showplaylist':false,'playlist':[{'title':'blalbla','url':'test'}]}" ></script>
<!-- SCM Music Player script end -->
What I want to do it's hide it and delete the extra space that gives to the bottom.
You need something like
#playerW {
display: none!important
}
I don't like using !important because it's usually a sign of poor code, but here I think it's required as the css properties for the scm player are being set by javascript. The other method might be:
html body iframe #playerW {
display: none;
}
This adds more specificity to the target element. You want to load this after the scm.css link in your template.
However I would also check that these things are not already configurable within your theme.
Based on your last comment (and looking at the current implementation of your theme) I have this hack
#scmframe {
display: block;
background-color: transparent;
position: fixed;
top: -30px; // change this from 0px
left: 0px;
width: 100%;
height: 120%; //change this from 100%
z-index: 1667;
}

Using WP web scraper with WordPress

I'm trying to use WP Web Scraper plugin with WP in my site www.eastwickpark.co.uk to get online ratings of the practice from another site
https://www.iwantgreatcare.org/gpsurgeries/eastwick-park-medical-practice
I used this code snippet
<img src="http://www.eastwickpark.co.uk/wp/wp-content/uploads/2015/11/iwantgreatcarelogo.png" />
<div>
[wpws url="https://www.iwantgreatcare.org/gpsurgeries/eastwick-park-medical-practice" query=".image-middle" basehref="1" ]
</div>
Then I used custom CSS in the themes stylesheet editor
.btn.blue,
div .btn.blue {
font-size: 16px;
padding: 8px 16px;
}
/*** Stars ***/
.sprite-icons.star-blue-outline {
background-image: url('http://www.eastwickpark.co.uk/wp/wp-content/uploads/2015/11/star-blue-outline.png');
width: 19px;
height: 17px;
}
.sprite-icons.star-blue-fill {
background-image: url('http://www.eastwickpark.co.uk/wp/wp-content/uploads/2015/11/star-blue.png');
width: 19px;
height: 17px;
}
.sprite-icons.star-blue-half {
background-image: url('http://www.eastwickpark.co.uk/wp/wp-content/uploads/2015/11/star-blue-half.png');
width: 19px;
height: 17px;
}
.sprite-icons.caret-white {
background-image: url('http://www.eastwickpark.co.uk/wp/wp-content/uploads/2015/11/caret-white.png');
width: 10px;
height: 14px;
}
I've got a problem with my CSS in that the button "wraps".
Tried to just get the star rating targeting the class "raty-rating-wrapper-readonly" part but then I get a whole load of vertical stars.
i.e. if i use
[wpws url="https://www.iwantgreatcare.org/gpsurgeries/eastwick-park-medical-practice" query=".raty-rating-wrapper-readonly" basehref="1" ]
I get a whole vertical list of 5 * images?
If I use image-middle div like this
[wpws url="https://www.iwantgreatcare.org/gpsurgeries/eastwick-park-medical-practice" query=".image-middle" basehref="1" ]
I get a weird wrap on the button.
Can't figure this out, and have to admit I'm not a CSS guru. Any insight would be gratefully received.
I've got a problem with my CSS in that the button "wraps"
The cause of the wrapping behaviour is due to <br> tag dynamically generated by WordPress. You can either fix it by following the guideline here: Stop WordPress automatically adding <br> tags to post content
The above post is a plus for you because it also removes the <p> tags that are dynamically generated. I just browsed through your code and found a lot of unwanted p tags.
Can't figure this out, and have to admit I'm not a CSS guru. Any
insight would be gratefully received.
Since you hinted for a CSS solution, a simple fix is to hide the br tags using #widgets .textwidget br { display: none; }. Alternatively #widgets .textwidget a { display: inline-flex; align-items: center } fixes the space and aligns the arrow image as the br tag is ignored inside and initial direction of flex is row.
Unwrapped button:

The need to use inherit in CSS

Been looking at a premium theme and see that for various text and elements on the page, when inspected - many have inherit and 0 for the values.
Why would these not be left blank if they are not required and automatically inherited from the parent? Does it perhaps save on load time?
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
font-family: inherit;
font-size: 100%;
font-style: inherit;
font-weight: inherit;
This is done to override browser defaults.
Most browsers themselves apply their own style declarations to make basic HTML pages look prettier. Unfortunately these style declarations often clash with how a designer wants a web page to look. The way to overcome this is to reset the styles to what they should be by default.
Example
A good example of this is with heading and p tags. Take the following example:
<h1>Hello, world!</h1>
<p>Woah, that's a big heading!</p>
Without any custom styling applied, these elements use styles provided by the browser. One of the styles used here is margin, and that's what's putting the large gaps between each element.
We can reset these ourselves by setting the margin to 0:
* {
margin: 0;
}
<h1>Hello, world!</h1>
<p>Woah, that's a big heading!</p>
Because of the need to reset such styles public stylesheets like Normalize.css exist, whose intention is to do nothing more than reset (and normalize) all elements to look the same across different browsers.

Random whitespace in Google Chrome extension

I have some CSS:
fieldset {
border-radius: 5px;
border: 3px solid blue;
padding: 5px;
margin: 0em;
}
legend {
font-weight: bold;
color: green;
}
#myform{
width: 330px;
margin: 0em;
}
body {
font-family: Arial, sans-serif;
}
When I embed it with <style>, it works perfectly fine:
But when I put the same CSS into a stylesheet and import it using <link>, I get some random whitespace:
I have removed the form elements completely, and there is still whitespace (although if I keep them in, there is considerably more of it). I used the Chrome developers console to check form and body height using $(body).css("height") (and the same for the form), and it gives me a number which is way too small to include the whitespace, but seems to match the height if the whitespace is ignored. Where is this coming from?
This seems to be a bug, when changing the margin of the body back and forth in the developers console it gets right again. Setting this property in the CSS doesn't have any effect at all.
A measly workaround would be creating a javascript file for your popup, like popup.js, and then change the margin in there after the popup window is loaded:
document.addEventListener('DOMContentLoaded', function() {
document.body.style.margin = '8px';
});
I took 8px as value because that's the standard value of a Chrome popup:
You should consider reporting this bug to the Chrome issues list.
put CSS with !important keyword
i.e.
#myform{
width: 330px !important;
margin: 0em !important;
}

Resources